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

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

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

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

Q&A

解決済

5回答

1160閲覧

プログラミング初心者 小数点以下を含む計算

T.T.T33

総合スコア2

Python

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

0グッド

0クリップ

投稿2021/06/25 06:37

編集2021/06/25 06:39

プログラミング初心者で、できる事できない事を色々探りながら進めている状態です。
ちょうど開始1週間目です。
以下の問題に解きました。
input()で数字を3つ入力する。例)1 80 40

最初の数字=商品の量(kg)
2つ目の数字=最初の売り上げパーセント
3つ目の数字=(売れ残った量のうち)2回目の売り上げパーセント

最後に売れ残った商品の量を求めます。

なので、1 80 40だと
1kgの商品が、最初は80%売れて、20%売れ残り、
残った0.2kgのうち2回目は40%売れたので、残った量は0.12kg(答え)となります。

以下のコードを打ちましたが、上手くいくときは上手くいき、ダメな時はダメです。
理由は小数点以下の話になり、小数点第3位くらいまで続くものは正確に答えが出ないです。

じゃあ
float('{:.2g}'.format(first_leftover))
このようなの要らないのでは、と思いましたが、これが無いと
たまに
1.20000000000000000006
とかになってしまいます。

皆さんはどのようにコードを書きますでしょうか?
また、分からない仕組み等は逐一ネット検索になってしまいます。
小数点以下切り捨てたいけどできない=>すぐ検索

になってしまいます。これは正しい学習法でしょうか。

coding: utf-8

Your code here!

import math

total,first_percent,second_percent = [int(x) for x in input().split()]

first_sale = total * (first_percent / 100)

first_leftover = total - first_sale

second_prep = float('{:.2g}'.format(first_leftover)) #2桁まで表示

second_sale = second_prep * (second_percent / 100)

second_leftover = second_prep - second_sale
Answer = float('{:.2g}'.format(second_leftover))
print(Answer)

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

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

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

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

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

ozwk

2021/06/25 07:02

> ダメな時はダメです だめなときの入力例をください
jbpb0

2021/06/25 07:15 編集

> 小数点第3位くらいまで続くものは正確に答えが出ない 計算は精度を落とさずにして、結果表示のところで必要な桁までにしたらいいのでは? first_sale = total * (first_percent / 100) first_leftover = total - first_sale second_sale = first_leftover * (second_percent / 100) second_leftover = first_leftover - second_sale print('{:.6f}'.format(second_leftover))
T.T.T33

2021/06/25 07:23

御二方ともありがとうございます。 濁しましたが、某サイトの問題でした(就活等の目的ではやってはいないですが)。 例えば1, 80, 40と打つとき0.12と求められます。 例えば10, 31, 52と打つとき、結果は3.312と求められますが、3.3(3.31?)と出てしまいました。 あまりコードの意味を理解してなかったので見落としていましたが、きっと jbpb0さんのように最後だけ変えればいいのでしょうね。
guest

回答5

0

有効数字を考え、小数点以下第何位まで表示ってことをしましょう。

浮動小数点数というのは、2進数で内部表現してます。
が、ニンゲン用に10進に変換するときに誤差が出ます

ぶっちゃけ、10進数の0.1は2進数では表現できません。

投稿2021/06/25 06:43

編集2021/06/25 06:45
y_waiwai

総合スコア87774

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

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

T.T.T33

2021/06/25 07:18

なるほどそのような実情があるのですね。その辺り可能な限り少しずつ考察していきます。ありがとうございました。
y_waiwai

2021/06/25 07:22

「浮動小数点数 誤差」なんかでぐぐると、そこらへんの解説が出てきます
T.T.T33

2021/06/25 07:26

ありがとうございます。検索してみます。
Zuishin

2021/06/25 07:54 編集

Python は少し事情が違います。 https://docs.python.org/ja/3/tutorial/floatingpoint.html > これは、ほとんどの人が必要と感じるよりも多すぎる桁数です。なので、Python は丸めた値を表示することで、桁数を扱いやすい範囲にとどめます 設問を見ると精度は 1/10000 に収まり、百分率での計算になるため、10 進数では小数点以下 4 桁まで対応すれば正確に表せるはずです。 元々の計算方法が間違っているのでは? 念のため 0.0001 から 0.9999 までを表示してみましたが、全て小数点以下 4 桁に収まりました。
ikadzuchi

2021/06/26 04:47

> Python は少し事情が違います。 いいえ。説明を読む限り、ある数値を表示する時に最も短い10進表現にするというだけの、他の言語でもやっている処理ですね。 > 0.0001 から 0.9999 までを表示してみましたが 10進数で入力した数がそのまま表示されるのは他の言語でも見られる一般的な挙動です。 今回問題になっているのは演算の結果において「10進数で切りの良い数(に最も近い2進数)」からのずれが出ることです。
Zuishin

2021/06/26 04:58

だから演算の仕方が悪いということでしょう。 結果は 1/10000 の精度に収まるので、その精度で表示されれば問題ありません。 10000 倍すれば整数の演算ができるということです。 それを最終的に求める値に戻しても端数が出ないことは確かめました。 具体的には次の演算で誤差が生じています。 > second_leftover = second_prep - second_sale 事情が違うというのは、C 言語と違って自動的に丸められるという意味です。
Zuishin

2021/06/26 05:08 編集

> 事情が違うというのは、C 言語と違って自動的に丸められるという意味です。 もう少し詳しく言うと、有効数字をこちらで指定しなくても、正しく計算すれば、この場合は自動的に 10 進法で小数点以下 4 桁以内に収まります。
ikadzuchi

2021/06/27 06:54

> 演算の仕方が悪い > 10000 倍すれば整数の演算ができる はい、それは問題ありません。 > C 言語と違って自動的に丸められる > 正しく計算すれば、この場合は自動的に ここが分かりません。 多くの言語で、正しく計算すれば(=ある10進小数に最も近い2進小数であれば)適切に丸めた値が表示されるものと思っているのですが、 そのような場合でもPython以外の言語は不要な桁まで表示するということですか? なおC言語だと手元の環境では逆に過剰に丸めていますね…。 double f=0.1; double g=0.01; printf("%g,%g,%g\n", g,f*f,f*f-g); printf("%.18f,%.18f,%.18f\n", g,f*f,f*f-g); で 0.01,0.01,1.73472e-18 0.010000000000000000,0.010000000000000002,0.000000000000000002 となります。 gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
Zuishin

2021/06/27 07:28 編集

何が言いたいのか意味が分かりませんが、過剰であれば適切ではないでしょう。 私が言いたいのは、問題になっているのは演算中の誤差であり、表示の際の誤差ではないということですが、この回答ではそのようにとれません。 > 小数点以下第何位まで表示ってことをしましょう。 これが回答の主旨ですが、本来の原因である「演算中の誤差」ではないところに注目していて、解決法としてはミスリードになっていると思います。 誤っているとまでは言えないので低評価はしていませんが、ずれているとは思っています。
ikadzuchi

2021/06/27 07:31

分からないなら本題でないので別に構いません。 回答については何も言っていません。 「Pythonは事情が違う」という点について、特にその他の言語と違う点が見受けられなかったので尋ねています。
Zuishin

2021/06/27 07:40 編集

わからないのは、あなたが何を言おうとしているかです。 > 小数点以下第何位まで表示ってことをしましょう。 Python ではこれをしなくてもいいということを「事情が違う」と表現しています。 C 言語と違って、フォーマット指定子不要で自動的にまるめられます。 逆にフォーマット指定することによって、より正確な値を表示することになります。 私がリンクしたところを見ればそう書いてあると思いますが。
ikadzuchi

2021/06/29 13:48

面倒になってきたので要点だけ。 なぜ様々ある言語の中でC言語と比較するのですか? フォーマット指定子がC言語で必須なのは丸めと無関係な話です。 C言語でもフォーマット指定子にgを使えば自動で丸められます。 丸めに関してPythonに特にその他の言語と違う点が見受けられません。
Zuishin

2021/06/29 13:56

C 言語 1 位の人の回答だからです。
Zuishin

2021/06/29 13:59

それとすでに述べたように、 > 小数点以下第何位まで表示ってことをしましょう。 に対するコメントです。 g を使って自動で丸めるという回答ではないので、ここで g を持ち出す意図がわかりません。
Zuishin

2021/06/29 14:00

それとすでに述べたように、Python では「フォーマット指定子を使わなくても自動で丸めるところ」が C 言語と違います。
Zuishin

2021/06/29 14:01

これだけ分割すれば読めますか? まだ長すぎますか?
ikadzuchi

2021/06/30 04:55

あなたは分割しないと長過ぎて文章が読めないんですね。了解しました。
ikadzuchi

2021/06/30 04:56

> C 言語 1 位の人の回答だからです。 なるほど分かりました。質問にも回答にも無関係なのに、比較対象がC言語であることが説明されずに分かるとあなたは思っているのですね。
ikadzuchi

2021/06/30 04:58

> > 小数点以下第何位まで表示ってことをしましょう。 > に対するコメントです。 > g を使って自動で丸めるという回答ではないので、ここで g を持ち出す意図がわかりません。 あなたの「自動的にまるめられます。」に対してgを持ち出しました。 C言語でも自動で丸めることができることを示す意図です。
ikadzuchi

2021/06/30 05:00

> それとすでに述べたように、Python では「フォーマット指定子を使わなくても自動で丸めるところ」が C 言語と違います。 すでに述べたように、フォーマット指定子がC言語で必須なのは丸めと無関係な話です。 C言語ではフォーマット指定子を選ぶことにより自動で丸めたり丸めなかったりすることができ、Pythonではフォーマットを指定したり指定しなかったりすることで自動で丸めたり丸めなかったりすることができます。
Zuishin

2021/06/30 06:14

あなたに合わせて十分短くしたのに、まだわからないようで困惑しています。 質問してきて「面倒」と言うような人にこちらは用事がないし、日本語が通じないならこちらこそ迷惑なんですが、まだ説明が必要なら、どこがわからないのかを端的に質問してください。
guest

0

ベストアンサー

ー 残った量は0.12kg(答え)となります。

Pythonの場合、どうしても十進法でやりたければ、decimal --- 十進固定及び浮動小数点数の算術演算を使うという方法もあります。

python

1import decimal 2 3total,first_percent,second_percent = [decimal.Decimal(x) for x in input().split()] 4 5first_sale = total * (first_percent / 100) 6first_leftover = total - first_sale 7second_sale = first_leftover * (second_percent / 100) 8 9second_leftover = first_leftover - second_sale 10print(second_leftover)

実行結果

python

1>>> print(second_leftover) 20.12

ただし、decimalはあまり使わないので、浮動小数点数では十進法の有限小数が二進法の有限小数では表せないということを理解しておいて下さい。

  • これは正しい学習法でしょうか。

まず、コンピュータのハードウェアとOSについて基本的な本を読んで置いた方が良いと思います。

投稿2021/06/25 13:05

ppaul

総合スコア24666

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

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

T.T.T33

2021/06/29 00:07

丁寧な解答をいただきありがとうございました。色々参考にさせていただきます。
guest

0

余り本題と関係ないですが
second_prep = float('{:.2g}'.format(first_leftover)) #2桁まで表示
この丸めは余計です


入力値はすべて整数ですから最初の売れ残りは小数点2桁まであれば良くて、
その次の売れ残り、つまり答えは4桁まであればいいことになります。

というわけで答えを2桁で切っていたら正確な答えが出ません。

投稿2021/06/25 06:57

編集2021/06/25 07:23
ozwk

総合スコア13521

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

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

T.T.T33

2021/06/25 07:18

ありがとうございます。こちらとしては何の情報でもシェアしていただけるのはありがたいです。
guest

0

また、分からない仕組み等は逐一ネット検索になってしまいます。

小数点以下切り捨てたいけどできない=>すぐ検索

未だに小数点以下を含む計算で問題が発生するとググってるので、回答する権利があるかどうか微妙ですが、学習の起点となる情報が他の回答にないので記述しておきます。

本件で気にされているのは、いわゆる「浮動小数点数」の誤差として知られている計算機の抱える問題です。
私たちが一般的に使用する 10 進数と計算機内部で計算に使用される 2 進数の変換時に発生する誤差のことを言っており、多くの場合、IEEE 754 で定義された手法で変換がなされています。

この IEEE 754 が非常に重要なので、都度ググりたくなければちゃんと読み込むと良いです。
結構お高いので私は入手を断念しましたw

昔はこの辺の話題が好きな人がいたんですけど、最近めっきり見ないんで最後に彼の回答をリンクしておきますね。

言語別?計算誤差に関して - raccy さんの回答

投稿2021/06/27 22:28

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

参考情報

プログラミングにおける数値計算はワナがいっぱい

投稿2021/06/25 23:44

katoy

総合スコア22324

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問