我有一个相当粗略的代码,必须或多或少随机生成一堆百分比,存储为十进制浮点数。也就是说,它决定材料一个占总数的13.307%,然后将其存储在dict中为0.13307。
麻烦的是,我永远无法将这些数字加起来只有一个。老实说,我不完全确定问题是什么。这可能与花车的性质有关。
这是令人讨厌的代码,在其所有过于复杂的荣耀中:
while not sum(atmosphere.values())>=1:
#Choose a material randomly
themat=random.choice(list(materials.values()))
#If the randomly chosen material is gaseous at our predicted temperature...
if themat.vapor < temp:
#Choose a random percentage that it will make up of our planet's atmosphere, then put it in the atmos dict.
atmosphere[themat]=round(random.uniform(0.001,0.5),5)
#Find out if the fractions add up to more than 1
difference=(sum(atmosphere.values())-1)
#If one does...
while difference > 0:
#Choose a random constituent
themat=random.choice(list(atmosphere.keys()))
#If that constituent has a higher fraction value than the amount we'd need to reduce the total to 1...
if atmosphere[themat]>(sum(atmosphere.values())-1):
#Subtract that much from it.
atmosphere[themat]-=difference
#Then break the loop, since we're done and otherwise we'd go on removing bits of the atmosphere forever.
break
else:
#Otherwise, halve its percentage and reduce difference by the amount we reduced the atmosphere
oldperc=atmosphere[themat]
atmosphere[themat]=oldperc/2
difference-=oldperc/2
#Then, finally, we correct any overcorrections the previous block made.
difference=(sum(atmosphere.values())-1)
if difference < 0:
#Choose a random mat
themat=random.choice(list(atmosphere.keys()))
#Then add enough to it that the total is 1.
atmosphere[themat]+=difference
很抱歉,如果我错过了一些显而易见的事情,或者我没有提供重要的信息,但我现在已经累了,而且我一直在努力解决这个问题。
答案 0 :(得分:5)
据我所知,你想要选择介于0.0和1.0之间的两个浮点数,使它们加到1.0。
这样做:
然后在浮点数中,S + L正好是1.0。
如果由于某种原因你在算法中首先获得最小数字S,则计算L = 1.0 - S然后S0 = 1.0 - L.然后L和S0恰好加起来为1.0。考虑S0是S的“圆形”版本。
如果要添加N个数字,每个介于0.0和1.0之间,并且期望操作X 1 + X 2 + ...和1.0 - X,这是一个替代解决方案 1 ...表现得像在数学中一样。
每次获得新数字X i 时,执行:X i ←1.0 - (1.0 - X i )。从那时起仅使用X i 的新值。此赋值将略微舍入X i ,以便在中间结果介于0.0和1.0之间的所有总和中表现良好。
编辑:完成上述值X 1 ,...,X N-1 后,计算X N as 1 - X 1 - ... - X N-1 。这个浮点计算将是精确的(尽管涉及浮点),因此您将完全具有X 1 + ... + X N = 1。
答案 1 :(得分:3)
从您的代码中看起来,您可能会随机生成行星大气,大概是某种游戏或某种东西。无论如何,它的随机性使我确信它不需要太精确。
所以我建议你不要使用花车,只需使用int
s然后上升到100.然后你会得到你的确切求和。对于任何数学,你只想在演员阵容中使用它们。
这不是一个选择吗?
如果您坚持使用花车,请继续阅读......
您使用浮动的问题如下:
浮点(在本例中为double)表示如下:
对应于double
的值:
所以,
您的号码为(1+M) * 2**(E)
(其中E
= e-offset
)
1+M
始终在1-2范围内。
因此,我们在每对2的幂(正和负)之间有相等间隔的数字,并且数字之间的间距随着指数E
的每次增加而加倍。
考虑一下,这意味着每个数字[(1,2),(2,4),(4,8), etc]
之间存在可表示的数字的恒定间距。这也适用于2的负幂,所以:
0.5 - 1
0.25 - 0.5
0.125 - 0.25
0.0625 - 0.125
etc.
在每个范围内,都有相同数量的数字。这意味着,如果您使用(0.25,0.5)
范围内的数字并将其添加到(0.5,1)
范围内的数字,那么您有50%的可能无法准确表示该数字。
如果对指数与D
相差的两个浮点数求和,则总和可以准确表示的概率为2 -D 。
如果你想表示范围0-1
,那么你必须非常小心你使用哪个浮点数(即强制分数的最后N
位为零,其中N
是E
)的函数。
如果沿着这条路走下去,那么你最终会在范围的顶部放置比底部更多的浮子。
另一种方法是决定你希望能够接近零。让我们说你想降到0.0001。
0.0001 =(1 + M)* 2 E
log 2 (0.0001)= -13.28771 ...
所以我们将-14用作最小指数。
然后要达到1,我们只将指数保留为-1。
所以现在我们有13个范围,每个范围的值都是我们可以求和的两个范围,而不必担心精度。
这也意味着,顶级系列还有213个我们可以使用的值。这显然不行。
因此,在选择一个浮点数后,将舍入到最接近的允许值 - 在这种情况下,通过 round 我只是将最后的13位设置为零,并将其全部放入一个函数中,并在将它们从rand
中取出后立即将其应用于您的数字。
这样的事情:
from ctypes import *
def roundf(x,bitsToRound):
i = cast(pointer(c_float(x)), POINTER(c_int32)).contents.value
bits = bin(i)
bits = bits[:-bitsToRound] + "0"*bitsToRound
i = int(bits,2)
y = cast(pointer(c_int32(i)), POINTER(c_float)).contents.value
return y
(来自维基百科的图片)
答案 2 :(得分:0)
由于浮点数以二进制表示形式存储在机器中,因此始终存在无法精确表示的数字。如果需要解决此限制,则必须使用一些使用自定义数据类型的数学库。
答案 3 :(得分:0)
最后,事实证明最简单的解决方案是改变问题。无论何时选中round(x,5)
,将总和精确到5位数的精确度,得到足够的结果。
答案 4 :(得分:-2)
浮标由两个幂表示。从python文档:“不幸的是,大多数小数部分不能完全表示为二进制分数”
http://docs.python.org/2/tutorial/floatingpoint.html
编辑:也许不是实际上试图达到1.0000000000000000000000,你应该通过在第三个小数位后切断任何东西来确定可接受的错误级别。您可以相对确定添加到1的值。使用此概念,您可以接受大于0.999且小于1.001的任何答案。
这可能不完美,但它可能是一个很好的解决方法,让你解决问题。