質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Q&A

解決済

2回答

2251閲覧

多項式の掛け算の結果がおかしくなる

Ryuuse

総合スコア27

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

1グッド

1クリップ

投稿2020/10/19 19:44

編集2020/10/19 21:00

多項式どうしを掛け算した結果を表示するプログラムを作っているのですが、思い通りに出来ません。
例えば、p1 = 3x^2 + 2x + 1、p3 = 3x^2 + 7x + 5、p4 = p1*p3とすると、結果が p4 = 3x^4 + 5x^3 + 18x^2 + 11x +5となります。この結果をよく見てみると、getMultipledメソッドにおける始めのループ処理では、p3の定数項の5とp1の各項との乗算が出来ていることが分かります。しかし、それ以降のループでは全てp3の項の係数を1として計算されているようです(2ループ目では7xの7を係数として計算がなされるはずです)。なぜこのような結果になってしまうのかがよく分かりません。もし分かれば教えてください。よろしくお願いします。ソースコードは以下の通りです。

public class Polynomial { int[] co; // 係数(coefficient)の配列 Polynomial() { co = new int[1]; co[0] = 0; } Polynomial(int[] co) { this.co = co; } Polynomial(int k2, int k1, int k0) { co = new int[3]; co[0] = k0; // 定数項 (0次の係数) co[1] = k1; // 1次の係数 co[2] = k2; // 2次の係数 } Polynomial getShifted(Polynomial poly, int num) { if (num < 1) return poly; int dim = co.length + num; int[] shiftedCo = new int[dim]; for (int i = 0; i < poly.co.length; i++) { shiftedCo[i + num] = co[i]; } for (int i = 0; i < num; i++) { shiftedCo[i] = 0; } return new Polynomial(shiftedCo); } Polynomial getMultiplied(Polynomial poly , int k){ int[] mul = new int[poly.co.length]; for(int i = 0; i < poly.co.length; i++){ mul[i] = 0; } for(int i = 0; i < poly.co.length; i++){ mul[i] = k*poly.co[i]; } return new Polynomial(mul); } public String toString() { StringBuffer sb = new StringBuffer(); for (int i = co.length - 1; i >= 2; i--) { sb.append(co[i]); sb.append("x^"); sb.append(i); sb.append(" + "); } sb.append(co[1] + "x" + " + " + co[0]); return new String(sb); // sb.toString() でも OK } Polynomial getAdded(Polynomial poly) { int dim = (this.co.length > poly.co.length) ? this.co.length : poly.co.length; int[] addedCo = new int[dim]; for (int i = 0; i < dim; i++) { addedCo[i] = 0; } for (int i = 0; i < this.co.length; i++) { addedCo[i] += this.co[i]; } for (int i = 0; i < poly.co.length; i++) { addedCo[i] += poly.co[i]; } return new Polynomial(addedCo); } static Polynomial plus(Polynomial left, Polynomial right) { int dim = (left.co.length > right.co.length) ? left.co.length : right.co.length; int[] retPolyCo = new int[dim]; for (int i = 0; i < dim; i++) { retPolyCo[i] = 0; } for (int i = 0; i < left.co.length; i++) { retPolyCo[i] += left.co[i]; } for (int i = 0; i < right.co.length; i++) { retPolyCo[i] += right.co[i]; } return new Polynomial(retPolyCo); } Polynomial getMultiplied(Polynomial poly){ int dim = (this.co.length - 1)+(poly.co.length -1); int[] dimCo = new int[dim]; Polynomial mul = new Polynomial(dimCo); Polynomial addedCo = new Polynomial(dimCo); for(int i = 0; i < poly.co.length; i++){ mul = getMultiplied(this , poly.co[i]); mul = getShifted(mul , i); addedCo = plus(mul, addedCo); } return addedCo; } public static void main(String[] args){ Polynomial p1 = new Polynomial(3, 2, 1); int[] co = {4, 5}; Polynomial p2 = new Polynomial(co); System.out.println("p1 = " + p1); System.out.println("p2 = " + p2); System.out.println("p1 + p2 = " + Polynomial.plus(p1, p2)); Polynomial p3 = p1.getAdded(p2); System.out.println("p1 = " + p1); System.out.println("p3 = " + p3); Polynomial p4 = p1.getMultiplied(p3); System.out.println("p4 = " + p4); System.out.println("p1 = " + p1); System.out.println("p3 = " + p3); System.out.println(p3.co[1]); } }
swordone👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

全体的に気になったので書き直してみました。
BigIntegerなどのように不変オブジェクトとし、計算結果はコピーを返す形です。
こうなると、計算のメソッド名もgetAddedなどではなく、「足し算」を明確にするためaddなどにしたいのが本音です。
Javaではint配列を生成した際、すべての要素が0で初期化されるため、手動で0初期化する必要はありません。

java

1public class Polynomial { 2 private final int[] co; // 係数(coefficient)の配列 3 Polynomial() { 4 co = new int[]{0}; 5 } 6 7 // 次数の高い順に並んでいることを想定し、逆順に並べて入れる 8 Polynomial(int... co) { 9 int n = co.length; 10 this.co = new int[n]; 11 for (int i = 0; i < n; i++) { 12 this.co[i] = co[n - i - 1]; 13 } 14 } 15 16 // 自分自身をシフトし、コピーを返す 17 Polynomial getShifted(int num) { 18 if (num < 1) 19 return this; 20 int dim = co.length + num; 21 int[] shiftedCo = new int[dim]; 22 for (int i = 0; i < poly.co.length; i++) { 23 shiftedCo[i + num] = co[i]; 24 } 25 return new Polynomial(shiftedCo); 26 } 27 28 // 多項式の整数倍 自分自身をk倍してコピーを返却 29 Polynomial getMultiplied(int k){ 30 if (k == 0) return new Polynomial(); 31 int[] mul = new int[co.length]; 32 for(int i = 0; i < co.length; i++){ 33 mul[i] = k*co[i]; 34 } 35 return new Polynomial(mul); 36 } 37 38 // 本当はここも自然な多項式の出力になるよういじりたかったが、面倒そうだったので放置 39 public String toString() { 40 StringBuffer sb = new StringBuffer(); 41 for (int i = co.length - 1; i >= 2; i--) { 42 sb.append(co[i]); 43 sb.append("x^"); 44 sb.append(i); 45 sb.append(" + "); 46 } 47 sb.append(co[1] + "x" + " + " + co[0]); 48 return new String(sb); // sb.toString() でも OK 49 } 50 51 Polynomial getAdded(Polynomial poly) { 52 int dim = Math.max(this.co.length, poly.co.length); 53 int[] addedCo = new int[dim]; 54 for (int i = 0; i < this.co.length; i++) { 55 addedCo[i] += this.co[i]; 56 } 57 for (int i = 0; i < poly.co.length; i++) { 58 addedCo[i] += poly.co[i]; 59 } 60 return new Polynomial(addedCo); 61 } 62 63 // plusメソッドはaddedメソッドでカバー可能のため削除 64 65 // shiftなんぞ使わずとも、2重ループで十分解決可能 66 Polynomial getMultiplied(Polynomial poly){ 67 int dim = (this.co.length - 1)+(poly.co.length -1); 68 int[] dimCo = new int[dim]; 69 for(int i = 0; i < this.co.length; i++){ 70 for (int j = 0; j < poly.co.length; j++) { 71 dimCo[i + j] += this.co[i] * poly.co[j]; 72 } 73 } 74 return new Polynomial(dimCo); 75 } 76}

投稿2020/10/20 02:00

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryuuse

2020/10/21 03:29

回答ありがとうございます。getShiftedを使わない発想は自分にはありませんでした。他にも色々な書き方がある事を学べました。
swordone

2020/10/21 05:08

書き方というより、ごく自然に分配法則を使っていっただけですけどね。
guest

0

ベストアンサー

getShiftedの実装ミスです。

Diff

1 Polynomial getShifted(Polynomial poly, int num) { 2 if (num < 1) 3 return poly; 4- int dim = co.length + num; 5+ int dim = poly.co.length + num; 6 int[] shiftedCo = new int[dim]; 7 for (int i = 0; i < poly.co.length; i++) { 8- shiftedCo[i + num] = co[i]; 9+ shiftedCo[i + num] = poly.co[i]; 10 } 11 for (int i = 0; i < num; i++) { 12 shiftedCo[i] = 0; 13 } 14 return new Polynomial(shiftedCo); 15 }

今回のケースでは、coはp1.coを、poly.coはp3.coを指しますから、混在していたわけです。
staticメソッドにしておけばこのようなミスは防げます。

追記
コメントでswordoneさんがご指摘のとおり、
引数polyを受け取らない非staticメソッドの方がJava的には自然かもしれません。

アドバイス

簡単にでもコメントを書きましょう。
第三者(あるいは未来のあなた)にとって読み易くなるだけでなく、思考の整理になります。

例えば次のように。(若干さぼっている部分もあります)

Java

1/** 2 * 各項の次数を一律に増やし、新しいオブジェクトを作って返す。 3 * Polynomial.getShifted(2x^2 + 3x, 2) => 2x^4 + 3x^2 4 * 5 * @param num シフト幅。正の数もしくは0。 6 */ 7private static Polynomial getShifted(Polynomial poly, int num) { 8 if (num < 1) { 9 // シフトの必要が無いとき 10 return poly; 11 } 12 13 // 新しい多項式オブジェクト 14 int dim = poly.co.length + num; 15 int[] shiftedCo = new int[dim]; 16 17 // num分だけずらして係数を代入する 18 for (int i = 0; i < poly.co.length; i++) { 19 shiftedCo[i + num] = poly.co[i]; 20 } 21 // 余った領域は0で埋める 22 for (int i = 0; i < num; i++) { 23 shiftedCo[i] = 0; // なおJavaの場合この処理は不要です。最初から要素の初期値が0なので。 24 } 25 26 return new Polynomial(shiftedCo); 27}

投稿2020/10/20 00:49

編集2020/10/20 01:44
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2020/10/20 01:30 編集

staticではなく、インスタンスメソッドとして、引数がシフト数だけのメソッドにしたほうが自然な気はします。
LouiS0616

2020/10/20 01:44 編集

インスタンスに一切の変更が生じない場合はstaticメソッドの方が分かり易いと個人的には思うんですが(引数をいじることは可能だけれども)、BigIntegerあたりのAPIを見る限りswordoneさんの感覚の方がJavaの雰囲気に合っている気がしますね。 回答に追記しました。コメントありがとうございます。
Ryuuse

2020/10/20 01:48

回答ありがとうございます。staticの使い方が良く分からなかったので、今回の質問である程度理解できました。またコメントも所々付けておけば、もっと早くミスに気付いていたと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問