1
print("Getting possible numbers")
import random

h1 = random.uniform(0,30)
h2 = random.uniform(0,30)
h3 = random.uniform(0,30)
t = random.uniform(0,30)

baset = .5 * t * h3
volumeti = baset * h2
baser = t * h2
volumer = h1 * baser
volumetotal = volumeti + volumer
c = 1

if volumetotal == 187.2:
  print("h1=", h1, "h2=", h2, "h3=", h3, "t=", t)

while volumetotal != 187.2:
 c += 1
 print("Wrong, trying again", c)

它会找到六棱柱的体积,但需要很长时间,我还没有得到输出。

4

6 回答 6

4

the loop:

while volumetotal != 187.2:
 c += 1
 print("Wrong, trying again", c)

is a trap. Once you get into the loop, you can never get out since you don't change volumetotal in the body of the loop.

Also note that checking for equality of floating point numbers can be tricky. Two numbers can be extremely close (1 part in 10**16) and still be different -- and numerical errors on that size are happening all the time.

于 2013-05-07T15:07:07.393 回答
1

你可能永远不会得到输出。

  1. 循环第一次失败永远不会让你再次生成数字
  2. 插入随机数以获得精确的解决方案不是很有效,并且可能永远不会返回结果。
  3. 用浮点数比较相等可能不是你想要的。阅读浮点数相等比较。

更好的解决方案是求解方程,以便您可以随机选择 3 个数字并求解第四个数字。也许像:

187.2 = .5 * t * h3 * h2 + h1 * t * h2
187.2 = h2(.5 * t * h3 + h1 * t)
h2 = 187.2 / (.5 * t * h3 + h1 * t)

然后生成t,h3h1计算h2

import random

print("Getting possible numbers")
h1 = random.uniform(0,30)
h3 = random.uniform(0,30)
t = random.uniform(0,30)
h2 = 187.2 / ((.5 * t * h3) + (h1 * t))
print("h1=", h1, "h2=", h2, "h3=", h3, "t=", t)
于 2013-05-07T15:09:32.870 回答
1

您还必须循环获取新的随机变量。此外,在处理浮点变量时,您必须接受一些小错误。看看这个:

print("Getting possible numbers")
import random

volumetotal = 0
c = 0

while abs(volumetotal - 187.2) >= 0.1:
  c += 1
  print("Attempt ", c)

  h1 = random.uniform(0,30)
  h2 = random.uniform(0,30)
  h3 = random.uniform(0,30)
  t = random.uniform(0,30)

  baset = .5 * t * h3
  volumeti = baset * h2
  baser = t * h2
  volumer = h1 * baser
  volumetotal = volumeti + volumer

print("h1=", h1, "h2=", h2, "h3=", h3, "t=", t)
于 2013-05-07T15:09:35.360 回答
0

修复无限循环问题后,您可以使用以下检查:

error = 0.00001
expected = 187.2
if expected - error <= volumetotal <= expected + error:
    print("Yay, this is roughly correct.") 

另一个技巧,但这个减少运行时间的技巧是跟踪先前选择的随机变量,并在尝试失败后将它们设置为上限/下限。因此:

# Pseudo-code
# if expected > desired:
#    set previously chosen random variables as the upper bound on the next 
#    iteration's random ranges.
# else:
#    set previously chosen random variables as the lower bound on the next
#    iteration's random ranges.
# Be sure to only shrink the range of the random selection until you converge on 
# a solution.
于 2013-05-07T15:10:31.797 回答
0

您无法测试两个浮点数之间的相等性,因为浮点算法精度差。您必须设置一个限制解决方案精度的 epsilon 值:

print("Getting possible numbers")
import random
import math

epsilon = 0.001
c = 1
h1 = 0
h2 = 0
h3 =0
t = 0

def solve():

    h1 = random.uniform(0,30)
    h2 = random.uniform(0,30)
    h3 = random.uniform(0,30)
    t = random.uniform(0,30)

    baset = .5 * t * h3

    volumeti = baset * h2

    baser = t * h2

    volumer = h1 * baser

    volumetotal = volumeti + volumer

    return volumetotal, h1, h2, h3, t




while math.fabs(volumetotal - 187.2) > epsilon: 
 global h1 
 global h2 
 global h3 
 global t

 c += 1
 volumetotal, h1, h2, h3, t = solve()
 print("Wrong, trying again", c)

print("found a solution : ")
print("h1=", h1, "h2=", h2, "h3=", h3, "t=", t)

编辑:添加输出全局变量。

但是,它是一种非常糟糕的求解方程的方法。如果您想保持随机方式,我建议您为确定性算法或遗传算法寻找梯度下降。

于 2013-05-07T15:18:20.200 回答
0

你有几个问题:

  • 首先也是最关键的,你的循环永远不会改变变量的值,所以它永远不会退出(因为它只是无限期地执行相同的测试。
  • 其次,几乎同样重要的是,如果您希望程序终止,则不应循环比较浮点数。这是因为浮点表示本质上是不准确的,因此您的比较将按照False您可能期望的那样进行评估True(例如 eumiro 在.3 + .3 + .3 == .9评估 to的评论中的示例False)。

第一个问题的解决方案很简单:您只需确保每次循环都重新计算变量。第二个同样简单:您需要测试值是否“足够接近”,而不是测试相等性。因此,选择一个容差值并将您的错误与该值进行比较,而不是要求完美。这两个都显示在下面的代码中(为了清楚起见,我将一些部分拆分为它们自己的函数)。我也做到了,所以c每 5000 次迭代才打印一次,这实际上使整个事情的运行速度提高了很多倍

print("Getting possible numbers")
import random

def get_variables():
    '''Initialize some random values.'''
    h1 = random.uniform(0,30)
    h2 = random.uniform(0,30)
    h3 = random.uniform(0,30)
    t = random.uniform(0,30)
    return h1, h2, h3, t

def calculate_volume(h1, h2, h3, t):
    '''Calculate the volume based on the given values.'''
    baset = .5 * t * h3
    volumeti = baset * h2
    baser = t * h2
    volumer = h1 * baser
    volumetotal = volumeti + volumer
    return volumetotal


volumetotal = 0
c = 0
tolerance = 0.00001 # Set the tolerance here!
h1 = h2 = h3 = t = None

while abs(volumetotal - 187.2) >= tolerance: 
    c += 1
    if c % 5000 == 0:
        print("Attempt ", c)

    h1, h2, h3, t = get_variables()
    volumetotal = calculate_volume(h1, h2, h3, t)

print ('h1 = {}\nh2 = {}\nh3 = {}\nt = {}\nc = {}\nv = {}'.format(
        h1, h2, h3, t, c, volumetotal))

请注意第 26 行,while 循环将abs(volumetotal - 187.2)(结果与预期结果的差异量)与0.00001(容差)进行比较。您可以将此容差设置为您喜欢的任何值,但容差越低,程序运行的时间就越长。

只是为了好玩,您可能真正想要的是为您的输出选择一个精度(h1h2等)。然后,您可以不使用随机数,而是以可预测的方式递增变量,直到达到容差范围内。这可能是我这样做的方式,而不是使用随机数,因为它至少保证您的循环将终止,并且它提供了对您的输入/输出的更多控制。

print("Getting possible numbers")
import itertools

def get_variable_permutations(precision):
    '''Get a permutation generator. The precision is # of decimal places.'''
    stepsize = 0.1**precision
    all_values = (v*stepsize for v in xrange(int(30/stepsize)))
    return itertools.permutations(all_values, 4)

def calculate_volume(h1, h2, h3, t):
    '''Calculate the volume based on the given values.'''
    baset = .5 * t * h3
    volumeti = baset * h2
    baser = t * h2
    volumer = h1 * baser
    volumetotal = volumeti + volumer
    return volumetotal


volumetotal = 0
c = 0
tolerance = 0.00001
precision = 5 # decimal place precision for h1, h2, h3, and t

for h1, h2, h3, t in get_variable_permutations(precision):
    c += 1
    if c % 5000 == 0: # So much faster!
        print("Attempt ", c)
    volumetotal = calculate_volume(h1, h2, h3, t)
    if abs(volumetotal - 187.2) <= tolerance:
        break

print ('h1 = {}\nh2 = {}\nh3 = {}\nt = {}\nc = {}\nv = {}'.format(
        h1, h2, h3, t, c, volumetotal))

你最大的加速(到目前为止)实际上来自于减少print语句。我的机器在不到一秒的时间内运行上述代码(公差为 0.00001,h1、h2、h3 和 t 的精度为小数点后 5 位)(在约 431,000 次迭代中找到几乎精确的解决方案)。打印每一行时,相同的计算大约需要 40 秒。

于 2013-05-07T16:24:43.160 回答