用于euler'项目的Python解决方案;s ex94

用于euler'项目的Python解决方案;s ex94,python,precision,trigonometry,Python,Precision,Trigonometry,注意:这是我几天前写的一篇文章的修订版,由于不完整而被关闭。我现在已经尽了最大努力对其进行优化,现在它应该是一个最小的可复制示例。 问题是: “很容易证明,不存在边长为整数且面积为整数的等边三角形。然而,几乎等边三角形5-5-6的面积为12个平方单位 我们将几乎等边三角形定义为两条边相等,第三条边相差不超过一个单位的三角形 求所有边长和面积为整数且周长不超过十亿(100000000)的几乎等边三角形的周长之和。” 问题的答案是518408346 我的结果比这个数字大得多。怎么会?在浏览了上一篇文

注意:这是我几天前写的一篇文章的修订版,由于不完整而被关闭。我现在已经尽了最大努力对其进行优化,现在它应该是一个最小的可复制示例。

问题是:

“很容易证明,不存在边长为整数且面积为整数的等边三角形。然而,几乎等边三角形5-5-6的面积为12个平方单位

我们将几乎等边三角形定义为两条边相等,第三条边相差不超过一个单位的三角形

求所有边长和面积为整数且周长不超过十亿(100000000)的几乎等边三角形的周长之和。”

问题的答案是
518408346

我的结果比这个数字大得多。怎么会?在浏览了上一篇文章暂停前的评论后,我认为这是由于一个浮点错误

我假设我的代码生成的数字是边界线整数,Python错误地将其视为整数。这就解释了为什么我的结果比正确的要大得多。我观察到,当小数点后的前导零的数量超过15时,python会这样做(例如,3.0000000000000005被视为3.0000000000000005,而3.(>15x0)被视为3.0。如果有办法更改此设置,我的方法可以工作。您同意吗?我认为,decimal模块在这里可能很有用,但我不确定如何将其用于此目的

这是我的代码:

sum_of_p=0


for i in range(2,333333334):

    if i%(5*10**6)==0:
        print(i)
    
    h=(i**2-((i+1)*0.5)**2)**0.5
    if int(h)==h:
        a=0.5*(i+1)*h
        if int(a)==a:
            sum_of_p+=3*i+1
        

    h=(i**2-((i-1)*0.5)**2)**0.5
    if int(h)==h:
        a=0.5*(i-1)*h
        if int(a)==a:
            sum_of_p+=3*i-1



print(sum_of_p)

我认为对于整数值问题,使用浮点不是一个好主意。下面是我找到的解决方案。如果您的版本或python低于3.8,那么您将不得不使用更慢的is_square_函数

import math

def is_square_(apositiveint):
# Taken from: 
# https://stackoverflow.com/questions/2489435/check-if-a-number-is-a-perfect-square
    x = apositiveint // 2
    seen = set([x])
    while x * x != apositiveint:
        x = (x + (apositiveint // x)) // 2
        if x in seen: return False
        seen.add(x)
    return True

def is_square(i: int) -> bool:
    return i == math.isqrt(i) ** 2

def check(a, b, c):
    """ return preimeter if area of triangle with sides of lengts a,b,c is integer """
    perimeter = a + b + c
    if perimeter % 2 == 1:
        # preimeter should be even
        return 0
    p = perimeter // 2
    # Use Heron's formula
    H = p*(p-a)*(p-b)*(p-c)
    if is_square(H):
        return perimeter
    return 0


sum_of_p = 0
max_i = 1000000000 // 3
for i in range(2, max_i + 1):

    if i % (10**5) == 0:
        print(i*100 / max_i )
    

    sum_of_p += check(i, i, i+1)
    sum_of_p += check(i, i, i-1)

print(sum_of_p)

我不确定int(h)==h是否可以很好地检查值是否没有小数部分。它应该是(h-math.floor(h))