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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

1748閲覧

リストの総和を1にする方法

kgaryoskuukto

総合スコア8

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/05/25 13:43

編集2018/05/26 04:27

(Python)ランダムに与えた非負整数を要素に持つリスト(リストの個数も任意に与える)の総和を1にしたい

Pythonにて,randintを用いて,ランダムに非負整数を,任意の数作成し,リストに格納した後,そのリストの総和を1にするような関数を作成しています.

任意個のランダム非負整数をリストとして作成することはrandintにより実現できました.
作成したリストの総和を1にするため,現在は,リストの総和で全要素を割っています(以降,この操作を正規化と呼びます).
理論的にはこの方法でリストの総和は1になりますが,実際にプログラムにてこれを実装すると,計算精度の問題か,正規化後のリストの総和をとると1とわずかに離れます.
作りたい関数は,リストの総和を厳密に1にしたいです.

どのような操作を行えばいいでしょうか.

[追記 5/26]
ご解答有難うございます.
有理数表現というものを調べてみました.
最初の投稿の内容が足りていなくて,申し訳ないのですが,リストの総和を厳密に1にした後,作られたそれぞれの分数(小数)を用いて,計算を行いたいです.
素人質問で申し訳ないのですが,その場合は,どうしてもどこかで丸め誤差が発生してしまうと言う認識で間違いないでしょうか?

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

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

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

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

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

guest

回答4

0

ベストアンサー

fractions をつかってみては?

python

1$ python3 2>>> from fractions import Fraction 3>>> list = [1/3, 2/3] 4>>> print(list[0]) 50.3333333333333333 6>>> print(list[0] + list[1]) 71.0 8 9>>> list = [Fraction(1,3), Fraction(2,3)] 10>>> print(list[0]) 111/3 12>>> print(list[0] + list[1]) 131

投稿2018/05/25 15:59

編集2018/05/26 04:44
katoy

総合スコア22324

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

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

0

厳密さを求めるのなら、sympyなどを使って、整数による有理数表現でがんばる他ないですね。

投稿2018/05/25 14:26

mkgrei

総合スコア8560

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

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

0

Decimalでは誤差が生じるのでこの用途には適してません。有限桁数の小数フォーマットは無限小数を表現できないため、他の方の回答のように有理数で処理するか、何らかの丸めの方法を考慮する必要があります。

ご指摘いただいたKSwordOfHaste様、ありがとうございました。

以下誤回答の記録

デフォルトのfloat型(浮動小数点型)で表現する限り、どうやっても計算誤差は出ます。

お望みなら、decimalモジュールを用いて正確に計算することはできます。

python

1>>> from decimal import Decimal 2>>> import random 3>>> lst = [Decimal(random.randint(0,49)) for _ in range(10)] 4>>> lst 5[Decimal('32'), Decimal('25'), Decimal('15'), Decimal('30'), Decimal('1'), Decimal('37'), Decimal('47'), Decimal('42'), Decimal('38'), Decimal('12')] 6>>> sum_lst = sum(lst) 7>>> [x/sum_lst for x in lst] 8[Decimal('0.1146953405017921146953405018'), Decimal('0.08960573476702508960573476703'), Decimal('0.05376344086021505376344086022'), Decimal('0.1075268817204301075268817204'), Decimal('0.003584229390681003584229390681'), Decimal('0.1326164874551971326164874552'), Decimal('0.1684587813620071684587813620'), Decimal('0.1505376344086021505376344086'), Decimal('0.1362007168458781362007168459'), Decimal('0.04301075268817204301075268817')] 9>>> sum([x/sum_lst for x in lst]) 10Decimal('1.000000000000000000000000000') 11>>> float(sum([x/sum_lst for x in lst])) 121.0

9.4. decimal — 十進固定及び浮動小数点数の算術演算 — Python 3.6.5 ドキュメント

投稿2018/05/25 13:52

編集2018/05/25 17:11
hayataka2049

総合スコア30933

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

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

KSwordOfHaste

2018/05/25 16:53

多分うっかりしておられるのだと思いますが、Decimalは除数が 2^n*5^m という条件を満たさないと無限少数となる(誤差が出る)可能性があり、この目的には使いにくい気がします。
hayataka2049

2018/05/25 17:04

その通りでした。ご指摘ありがとうございます。
guest

0

既に理解されているようですが、浮動小数点の場合、計算誤差があるので、常に合計が 1.0 になるとは限りません。良く知られている事として、 0.1 を 10回加算しても 1.0 になりません。 (0.1 は二進数で正確に表現できない)
どこで丸めるか、検討すべきと思います。

[追記]
ある程度の有限桁と割り切るならば、分母を十分に大きな整数とし、分子も整数とすれば、丸め誤差が無くなる(?)と思います。計算上の端数は、僅かなので、適当に振り分けるという方法は、解決になるでしょうか。

投稿2018/05/25 13:51

編集2018/05/26 08:52
pepperleaf

総合スコア6383

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問