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

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

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

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

10167閲覧

pythonで32bitの浮動小数点の計算をしたい(Cのfloatでの計算結果と同じにしたい)

marymills

総合スコア18

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/01/21 01:58

C原語===========================
float A = 839.896912;
float B = 0.25000;
float E = 1.000000;
int c = 2480;
int d = 2474;
float g = (A + c * B) / E;
float f = (A + d * B) / E;
printf("g is %f\n", g);
printf("f is %f\n", f);

g is 1459.896973
f is 1458.396973

上記のC原語と同じ計算をしたくpythonのソースを書きましたが計算結果が合いません

python================
import numpy as np
A = 839.896912
B = 0.25000
E = 1.000000
c = 2480
d = 2474
g = (A + c * B) / E
f = (A + d * B) / E
print(g)
print(f)

g is 1459.8969120000002
f is 1458.3969120000002

double型で計算しているため、違いがあることまでわかりましたが
その後の解決方法がわかりません。

やってみたこと(numpyのfloat32)
g = (np.float32(A) + c * np.float32(B)) / np.float32(E)
f = (np.float32(A) + d * np.float32(B)) / np.float32(E)
print("g is ",g)
print("f is ",f)

g is 1459.89691162
f is 1458.39691162

計算結果をC原語と同じにするにはどうしたら良いのでしょうか?

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

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

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

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

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

maisumakun

2019/01/21 02:00

「何のために」精度を落としたfloatとして計算したいのでしょうか。
marymills

2019/01/21 02:31

もともとはCでバイナリファイルを4バイトづつ読み込み(上記Aは0x4451f967)をfloatで計算してその結果を出しているので、同じように計算し値を出したいということになります。
guest

回答2

0

以下のようにすれば、Cのprint結果と一致はします。
ただし、floatの10進有効桁はたかだか6,7桁しかないので、小数以下6桁出しても下位は意味のない値となります。

Python

1import numpy as np 2 3A = 839.896912 4B = 0.25000 5E = 1.000000 6c = 2480 7d = 2474 8 9g = (np.float32(A) + c * np.float32(B)) / np.float32(E) 10f = (np.float32(A) + d * np.float32(B)) / np.float32(E) 11 12g = np.float32(g) 13f = np.float32(f) 14print('{:.6f}'.format(g)) # 1459.896973 15print('{:.6f}'.format(f)) # 1458.396973

投稿2019/01/21 02:29

can110

総合スコア38234

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

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

marymills

2019/01/21 06:55

この方法でCのprint結果と同じになりました。ありがとうごいます。
guest

0

ベストアンサー

結果が異なる点について

C言語ではintとfloatの乗算では両方の値がfloatへ変換された上で演算されますが、numpy.float32はintと乗算すると結果がfloat64(多くのCの実装におけるdouble型)になるようです。(Pythonの整数型(int)が多倍長精度であることに関係するのかも知れません。)

まず計算結果そのものを合わせるにはCと同じ規則で(floatの精度で)演算結果が求まるように注意深く式を記述しなければならないと思います。

Python

1from numpy import float32 2 3A = 839.896912 4B = 0.25 5E = 1.0 6c = 2480 7d = 2474 8 9## NG 10 11g = (float32(A) + c * float32(B)) / float32(E) 12print(type(g), g) # ==> <class 'numpy.float64'> 1459.8969116210938 13 14## OK 15 16g = (float32(A) + float32(c) * float32(B)) / float32(E) 17print(type(g), g) # ==> <class 'numpy.float32'> 1459.897

余談?: 値が同じでも文字列化(フォーマット)の仕様により違う値に見える

例え同一の値が得られたとしても、C言語でのprintfの結果に一致させるのはPythonでは容易ではないと思います。浮動小数点数を印字する際の文字列への変換仕様が異なるからです。printfの仕様(%fとすると小数点以下6位まで印字されるとか)を前提としてcan110さん回答のように小数点以下の桁数をformatに指定するのが簡単な方法だと思います。しかし%gや%eなど任意の数値・フォーマットについてCのprintfと同じ結果を表示するのはなかなか難しいのではないでしょうか?

ということで、かなりヘンテコな方法かも知れませんが「Cのsprintfをpythonから呼び出してしまうのはどうだろう」と思いやってみました。ctypesモジュールは使ったことないのでおかしな実装をしているかも知れません。なおスミマセンガ下記はWindows限定のコードです。Cのランタイムmsvcrtを使うコードを明示的に書いてしまってます。

Python

1from ctypes import * 2libc = cdll.msvcrt 3 4def format_double(fmt, f): 5 charset = 'latin1' 6 _buffer = create_string_buffer(100) 7 _fmt = bytes(fmt, encoding=charset) 8 libc.sprintf(_buffer, _fmt, c_double(f)) 9 return str(_buffer.value, encoding=charset) 10 11 12A = float32(839.896912) 13B = float32(0.25) 14E = float32(1.0) 15c = 2480 16d = 2474 17 18g = float32((A + float32(c) * B) / E) 19f = float32((A + float32(d) * B) / E) 20print('--python--') 21print('g is', g) 22print('f is', f) 23print('--sprintf--') 24print(format_double("g is %f", g)) 25print(format_double("f is %f", f))

cmd

1> python test.py 2--python-- 3g is 1459.897 4f is 1458.397 5--sprintf-- 6g is 1459.896973 7f is 1458.396973

(Windows10 64bit, CPython 3.7)

sprintfにdoubleへ変換したものを渡してますがprintfなどにfloatを渡しても実際にはdoubleへ変換されたものが引数となるためこうしています。(自分の知識はCの規格書を正確に把握しているレベルではありません。msvcrtでは%fでfloatもdoubleも印字できることから前述のようになっているはずと判断しているにすぎません。)

投稿2019/01/21 04:56

編集2019/01/21 05:13
KSwordOfHaste

総合スコア18392

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

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

marymills

2019/01/21 06:52

詳しく説明ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問