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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

3回答

2512閲覧

POW関数の計算結果が条件によって変わる理由を教えてください

NKJSM

総合スコア58

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2021/08/05 02:30

編集2021/08/05 05:00

Arduino UNOのPOW関数なのですが、特定の条件で1小さい値になってしまう原因がわかりません。

16進数の文字列を文字と桁から数値に変更するためにPOWを使ってプログラムを書いていた時なのですが、数値がおかしかったので調べると16の2乗が255に、16の1乗が15となり、16の0乗は1となりました。(プログラム中☆の物)。

それから色々試した結果。返り値を正しくDouble型で宣言すると正しい計算結果が得られたので、小数点以下が悪さしているのはわかるのですが、int型であってもPOWのexponent部を数値で与えるとずれませんでした(△)。
整数の整数乗で小数点以下が悪さをするのもあまり納得できていませんが、引数が実質同じに思える☆と△で結果が異なることが全く意味が分からなかったのでご教授願います。

複数の条件下で16の2乗、1乗、0乗をしてモニタに表示するだけのプログラム
int buflen;
int ans=0;
int ansint=0;
double ansdouble=0;

void setup() {
Serial.begin(9600);
}

void loop() {
buflen=3;
for(int i=0;i<buflen;i++){
if(i==0)ans=pow(16,2); \△
if(i==1)ans=pow(16,1);
if(i==2)ans=pow(16,0);
ansint=pow(16,buflen-1-i); \☆
ansdouble=pow(16,buflen-1-i); \〇
Serial.print(ans);
Serial.print(" ");
Serial.print(ansint);
Serial.print(" ");
Serial.print(ansdouble);
Serial.print("\n");
}
delay(100000);
}

シリアルモニタ(△ ☆ 〇):
256 255 256.00
16 15 16.00
1 1 1.00

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

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

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

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

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

guest

回答3

0

Arduino UNO では、double型 を指定しても float型 で演算します
Arduino DUE では、double型 で演算されるので誤差はでていません

Serial.print で double(float) 表示をする場合 四捨五入がおこなわれ
double(float)型 を int型 に変換した場合 小数が切り捨てられます

確認プログラム

void setup() { double ans; unsigned char i; Serial.begin(9600); Serial.println("Arduino Program Start !!"); Serial.println("double(float) \t\t\t\t\t\t\t\t unsigned int"); for ( i=0 ; i<=16 ; i++ ){ ans = pow( 2 , i ); Serial.print( ans , 30 ); Serial.print("\t\t"); Serial.print( ans ); // Serial.print( ans , 2 ); Serial.print(" \t"); Serial.print( ans , 0 ); Serial.print("\t\t"); Serial.print( (unsigned int)ans , DEC ); Serial.println(); } Serial.println("End"); } void loop() { }

double(float)型 , 小数第3位を四捨五入 , 小数第1位を四捨五入 , int型へ変換(小数切り捨て)

Arduino UNO 実行結果

Arduino Program Start !!
double(float)
1.000000000000000000000000000000 1.00 1 1
2.000000000000000000000000000000 2.00 2 2
3.999999523162841796875000000000 4.00 4 3
7.999998092651367187500000000000 8.00 8 7
15.999996185302734375000000000000 16.00 16 15
31.999988555908203125000000000000 32.00 32 31
63.999977111816406250000000000000 64.00 64 63
127.999954223632812500000000000000 128.00 128 127
255.999908447265625000000000000000 256.00 256 255
511.999633789062500000000000000000 512.00 512 511
1023.999267578125000000000000000000 1024.00 1024 1023
2047.998535156250000000000000000000 2048.00 2048 2047
4095.997070312500000000000000000000 4096.00 4096 4095
8192.000000000000000000000000000000 8192.00 8192 8192
16383.988281250000000000000000000000 16383.99 16384 16383
32767.976562500000000000000000000000 32767.98 32768 32767
65535.953125000000000000000000000000 65535.95 65536 65535
End

Arduino DUE 実行結果

Arduino Program Start !!
double(float)
1.000000000000000000000000000000 1.00 1 1
2.000000000000000000000000000000 2.00 2 2
4.000000000000000000000000000000 4.00 4 4
8.000000000000000000000000000000 8.00 8 8
16.000000000000000000000000000000 16.00 16 16
32.000000000000000000000000000000 32.00 32 32
64.000000000000000000000000000000 64.00 64 64
128.000000000000000000000000000000 128.00 128 128
256.000000000000000000000000000000 256.00 256 256
512.000000000000000000000000000000 512.00 512 512
1024.000000000000000000000000000000 1024.00 1024 1024
2048.000000000000000000000000000000 2048.00 2048 2048
4096.000000000000000000000000000000 4096.00 4096 4096
8192.000000000000000000000000000000 8192.00 8192 8192
16384.000000000000000000000000000000 16384.00 16384 16384
32768.000000000000000000000000000000 32768.00 32768 32768
65536.000000000000000000000000000000 65536.00 65536 65536
End

投稿2021/08/05 18:41

koujikuu

総合スコア401

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

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

0

ベストアンサー

pow(16,2)
などの実際の値が入っているものは、コンパイル時に計算され内部では定数化されているようです。

pow(16, buflen - 1 - i)
の方は、プログラム内でpow関数が呼び出され、実数から整数変換され丸めが行われた結果が入る。
1小さいのはこの丸め処理のためだろうと思われます。
(こちらについてはnac_tnkと同じ理由です)

そのため
256 255
16 15
の部分で違いが出たのだと思います。

ただ計算結果が異なるのは、コンパイル時計算の不具合のような気もしますが。

投稿2021/08/05 07:16

ta.fu

総合スコア1722

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

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

0

pow関数は

double pow(float base, float exponent);

となっています。
つまり、戻り値が255.99999998
のような値なのでしょう。

Serial.printは、表示桁以下の位で四捨五入をしてくれます。

Serial.print((int)ansdouble);//intにしてから表示
Serial.print(ansdouble,20);//小数点以下20桁まで表示

あたりも表示させると判りやすいと思います。

投稿2021/08/05 04:07

nac_tnk

総合スコア494

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問