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

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

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

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

Q&A

解決済

3回答

1415閲覧

str型をfloat型に変換すると、文字数が増える

penpen88

総合スコア18

Python

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

1グッド

2クリップ

投稿2023/11/14 09:43

編集2023/11/14 09:55

実現したいこと

小数点以下3ケタまでにしたいが、増えてしまいます。

151.671 151.651 151.701
と本来はなってほしいですが、

151.671 151.65099999999998 151.701
となってしまいます。

何がおかしいのでしょうか
みた方が早いと思いますので、コード→結果→前提の順で記載します。

該当のソースコード

python

1x = 151.67168989437898493880 2sell = str(x)[:7] #売り注文価格(この値段で売却する) 3buy1 = float(buy)-0.02 #買い価格(この値段になったら買いたい) 4buy2 = float(buy)+0.03 #損切り価格(この値段になったら買って手放したい)

発生している問題・エラーメッセージ

151.671 151.65099999999998 151.701 #151.671 151.651 151.701 と本来はなってほしいです

前提

値段は全て、小数点以下3桁に設定する必要があります。

ある数 x(十数桁) を自動取得して、最初の7文字だけ切り取って売る値段に設定し、売る値段の
+0.02円を決済価格(買い戻す値段)
-0.03円を損切り値と設定します。

sell1 の後ろに[:7]をつければ解決するのですが、
どう解決しますかという質問ではなく
なぜ小数点以下3桁にならないのか、という質問になります。

補足情報(FW/ツールのバージョンなど)

mac OS
python

tatsu99👍を押しています

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

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

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

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

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

melian

2023/11/14 09:54

15. 浮動小数点演算、その問題と制限 — Python 3.11.6 ドキュメント https://docs.python.org/ja/3.11/tutorial/floatingpoint.html > 表示された結果が正確に 1/10 であるように見えたとしても、実際に格納されている値は最も近く表現できる二進小数であるということだけは覚えておいてください。 > > 幾つかの異なる10進数の値が、同じ2進有理数の近似値を共有しています。例えば、0.1 と 0.10000000000000001 と 0.1000000000000000055511151231257827021181583404541015625 はどれも 3602879701896397 / 2 ** 55 に近似されます。同じ近似値を共有しているので、どの10進数の値も eval(repr(x)) == x という条件を満たしたまま同じように表示されます。 > > 昔の Python は、プロンプトと repr() ビルトイン関数は 17 桁の有効数字を持つ 0.10000000000000001 のような10進数の値を選んで表示していました。 Python 3.1 からは、ほとんどの場面で 0.1 のような最も短い桁数の10進数の値を選ぶようになりました。 > > この動作は2進数の浮動小数点にとってはごく自然なものです。これは Python のバグではありませんし、あなたのコードのバグでもありません。ハードウェアの浮動小数点演算をサポートしている全ての言語で同じ種類の問題を見つけることができます (いくつかの言語ではデフォルトの、あるいはどの出力モードを選んでも、この差を 表示しないかもしれませんが)。
penpen88

2023/11/16 14:21

ありがとうございます!
guest

回答3

0

ベストアンサー

float型は2進数浮動小数点なので、Σ(2のi乗) の有限個の和(※)で表せる物だけが正確に表現できます(あと指数部の範囲もあるのでそれも範囲内)。

※:多くの実装では2のべき乗の指数が連続する53個までの和なので、以下その前提で。

整数は、2の53乗未満であれば正確に表現できます。
2のべき乗の倍数なら値がそれ以上でもOKかもしれません。例えば2の100乗ちょうどならOKで、それから1引くと駄目。

小数部分は、0.5, 0.25, 0.125, 0.0625, ..... の連続する53個以内の和で表せれば良いのですが、
例えば、10進数の0.1は、連続する53個以内の和では表現できずに2進数では循環小数になり、正確な0.1は扱えません。その近似した数を10進数表現に変換すると、数値の下の方に誤差として出てくることになります。

10進数の小数点以下のある数字をプログラムで扱う時は、
案1:小数点の位置をずらして内部では整数の範囲で扱う
案2:10進小数を10進数のままで計算する10進計算ライブラリを使う
案3:誤差は我慢する
のどれかです。

案1は例えば、人間の身長の測定結果は普通ミリの単位までなので、センチメートルでなくミリメートルで記録すれば小数を扱わなくて済みます。必要があれば、表示の時にセンチメートル単位に変換して表示します。

案2は多くの言語に標準で備わっているはず。ただし、10進小数ライブラリを使うと加減乗除が機械語レベルではfloatだと1命令で済むところがサブルーチン呼び出しになるので、速度が非常に遅くなります。
質問にお書きの用途だと問題にならないと思いますが、数値計算で大きな回数繰り返すと、いつまでも終わらないと言うことになるかも知れません。

投稿2023/11/14 11:16

otn

総合スコア86319

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

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

otn

2023/11/16 14:37

> 10進数の小数点以下のある数字をプログラムで扱う時は、 > のどれかです。 と書きましたが、「小数点以下は0.5しかあり得ない」などのケースでは上述の通りfloatでも誤差は出ないので、 もちろんそのままfloatでも良いです。 例:リーグ戦で勝てば1点、引き分けなら0.5点ずつというケースでの勝ち点計算
guest

0

回答でなくて、すみません。
本件のような場合、decimal型を利用すると、簡単にあなたの目的が達せられるかと思います。
違っていたらスルーしてください。
decimal型
使い方

以下、使用例です。

python3

1from decimal import * 2 3x = 151.67168989437898493880 4sell = str(x)[:7] #売り注文価格(この値段で売却する) 5buy = Decimal(sell) 6buy1 = buy - Decimal("0.02") 7buy2 = buy + Decimal("0.03") 8print(buy,buy1,buy2) 9

結果
151.671 151.651 151.701

投稿2023/11/14 10:07

編集2023/11/14 10:24
tatsu99

総合スコア5540

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

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

penpen88

2023/11/14 12:56

ご回答ありがとうございます そのようにすると、小数点以下3桁になってくれますね。 さて、この buy1 を変数として、seleniumを使い、 element.send_keys(buy1)  という風に購入画面に入力します すると、 'decimal.Decimal' object is not iterable が出てきますが、変数として使うためには違う型に置き換える必要があるのでしょうか
tatsu99

2023/11/14 13:34

seleniumは使ったことがないので、よくわかりませんが いままで、buy1がfloat型で、element.send_keys(buy1) が正常に動作するなら element.send_keys(float(buy1)) でOKかと思います。 只、個人的には、float型自体が信頼がおけないので、 element.send_keys(str(buy1)) で正常に動作するなら、こちらの方が安全です。 decmal型の1.2をfloat型に変換したときに、1.19999999になるかもしれません。 decmal型の1.2を文字列に変換した場合は、1.2になることが担保されています。
penpen88

2023/11/16 14:20 編集

さらにstr型にするのですね! 理由を説明してくれ方をBAにさせて頂きましたが、tatsuさんもご回答ありがとうございました。助かりました。
guest

0

丸め誤差を参照してください.

以下対処例

python

1from fractions import Fraction 2 3x = 151.67168989437898493880 4 5_x = Fraction(str(x)[:7]) 6_sell1 = _x - Fraction(2, 100) 7_sell2 = _x + Fraction(3, 100) 8 9print(_x, _sell1, _sell2, sep=', ') # 151671/1000, 151651/1000, 151701/1000 10print(float(_x), float(_sell1), float(_sell2), sep=', ') # 151.671, 151.651, 151.701

投稿2023/11/14 09:51

編集2023/11/14 10:05
PondVillege

総合スコア1581

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

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

penpen88

2023/11/16 14:21

勉強になりました。ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問