Sch*_*ote 2 python math floating-point python-3.x
我有一个相当粗略的代码,必须或多或少随机生成一堆百分比,存储为十进制浮点数.也就是说,它决定材料一个占总数的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
Run Code Online (Sandbox Code Playgroud)
对不起,如果我错过了一些显而易见的事情,或者我没有提供一些重要的信息,但我现在很累,而且我一直在努力解决这个问题.
我知道你想要在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 Ñ如1 - X 1 - ... - X N-1 .这个浮点计算将是精确的(尽管涉及浮点),因此您将完全具有X 1 + ... + X N = 1.
从您的代码看来,您正在随机生成行星大气,大概是为了某种游戏或其他东西。无论如何,它的随机性让我相信它不需要太准确。
所以我建议你不要使用浮点数,只使用ints 并达到 100。然后你会得到你的确切总和。对于任何你想在 just cast 中使用它们的数学。
这不是一个选择吗?
如果您坚持使用浮点数,请继续阅读...
您使用浮动的问题如下:
浮点数(在本例中为双精度)表示如下:

对应于 adouble的值:

所以,
你的号码是(1+M) * 2**(E)(其中E= e-offset)
1+M 始终在 1-2 范围内。
因此,我们在每对 2 的幂(正和负)之间有等间距的数字,并且数字之间的间距随着指数 的每增加一倍而加倍E。
想想看,这意味着每个数字之间的可表示数字的间距是恒定的[(1,2),(2,4),(4,8), etc]。这也适用于二的负幂,所以:
0.5 - 1
0.25 - 0.5
0.125 - 0.25
0.0625 - 0.125
etc.
Run Code Online (Sandbox Code Playgroud)
并且在每个范围内,都有相同数量的数字。这意味着,如果您将范围内的数字(0.25,0.5)添加到范围内的数字中(0.5,1),那么您有 50% 的机会无法准确表示该数字。
如果对两个指数相差 的浮点数求和D,则总和完全可表示的可能性为 2 -D。
如果你想表示范围0-1,那么你必须非常小心你使用的浮点数(即强制N分数的最后一位为零,其中N是 的函数E)。
如果你沿着这条路线走下去,那么你最终会在范围顶部比底部获得更多的浮点数。
另一种方法是决定您希望能够接近零的程度。假设您想降低到 0.0001。
0.0001 = (1+M) * 2 E
日志2 (0.0001) = -13.28771...
所以我们将使用 -14 作为我们的最小指数。
然后要达到 1,我们只需将指数保留为 -1。
所以现在我们有 13 个范围,每个范围的值是下一个的两倍,我们可以求和而不必担心精度。
这也意味着,顶部范围还有 213 个我们可以使用的值。这显然不行。
因此,在选择一个浮点数后,然后将其舍入到最接近的允许值 - 在这种情况下,舍入我只是将最后 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
Run Code Online (Sandbox Code Playgroud)
(图片来自维基百科)