在C语言中如何避免舍入值?

koaltpgm  于 2023-01-20  发布在  其他
关注(0)|答案(3)|浏览(201)

我为此更新了代码:

#include <stdio.h>
int IsRightTriangle(float x,float y,float z )
{
    
    int result;
    
    if( ((x*x)+(y*y)-(z*z)>0.999 && (x*x)+(y*y)-(z*z)<1)  || ((x*x)+(z*z)-(y*y)>0.999 && (x*x)+(z*z)-(y*y)<1) || ((y*y)+(z*z)-(x*x)>0.999 &&(y*y)+(z*z)-(x*x)<1)) {
      
        result = 1; 
        return  result ;      
    } else { 
        result =0 ;
        return result;
    }
}
  • 但小数仍然有同样的问题-例如:运行测试:是直角三角形(边1 =15.26,边2 =8.00,边3 =13.00)--失败
    我试图写一个代码,检查三角形是否正确(使用小数值)。
    这是我的代码,问题是它总是舍入浮点数,我能在里面修改什么呢?
int IsRightTriangle(float x, float y, float z)
{
    int result;
    
    if((x*x) + (y*y) == (z*z) || (x*x) + (z*z) == (y*y) || (y*y) + (z*z) == (x*x)) {
        result = 1; 
        return result ;   
    }
    else { 
        result =0 ;
        return result;
    }
}
0lvr5msh

0lvr5msh1#

你不可能避免四舍五入。我重复一遍:你无法避免,这不可能
浮点数中只有一定数量的位。
如果我们假设浮点数是十进制的而不是二进制的,那么问题的十进制版本如下:
当我写if(x + y + z == 1)时,1/3 + 1/3 + 1/3 == 1吗?不,不是根据计算机,因为1/3是0.3333333,只有一定数量的数字,它加起来是0.999999,而不是1。
这是很常见的只是添加一些“容差范围”作为一个快速的解决方案。而不是if(x + y + z == 1)你可以写if(x + y + z > 0.9999 && x + y + z < 1.0001)这往往是足够好的,特别是对电脑游戏。你需要多少个9和0?嗯,只是写几个,然后玩游戏,看看它是否感觉正确。
对于某些应用程序,这可能不合适,然后您必须发明一种完全不同的方法来完成您正在尝试做的任何事情。例如,您可能将所有数字存储为有理数(分子和分母,也叫分数)而不是浮点数。有理数可以精确计算-如果分子和分母不溢出。C不t没有内置有理数,所以您需要编写自己的库函数,如struct rationalvoid rational_add(struct rational *a, struct rational *b)等。

ql3eal8s

ql3eal8s2#

这里有两个问题,答案都不是你想设法避免舍入,事实上,你可能需要做一些精心选择的舍入。
第一个问题是,没有一个有限精度浮点表示法可以精确地表示每一个分数,尤其是不可能精确地表示像sqrt(233)这样的无理数。
你试着在一个边长为8、13、平方根为233的三角形上测试你的程序。从数学上讲,这是一个完美的直角三角形,但是你不可能让你的程序测试这个直角三角形,因为你在问这个问题的时候不能说“233的平方根”。你肯定不能说155.26。你可以试试15.26434。但这是不准确的,就像15.264337522473748或15.2643375224737480252559487一样,没有一个有限表示是绝对准确的。
第二个问题是,大多数分数的表示,固有的不精确性意味着,你很少会发现,比如说,x*x + y*y,正好等于z*z,这是一个比较浮点数相等的例子,你可能不想尝试去做。(你会经常听到这样的说法:你应该“永远不要比较浮点数是否相等”,这作为一条经验法则并不太坏,但是还有很多话要说。)
您尝试将比较代码更新为

if(x*x + y*y - z*z > 0.999 && x*x + y*y - z*z < 1 || … )

但这也不完全正确,如果量x*x + y*yz*z几乎相等,它们的差将接近于0,尽管它可能落在两边,所以你要做的更像是

if(x*x + y*y - z*z > -.001 && x*x + y*y - z*z < 0.001 || … )

这在某种程度上可能是可行的。你可以通过以下方式简化它(避免重复的子表达式):

if(fabs(x*x + y*y - z*z) < 0.001 || … )

然而,使用像0.001这样的固定精度阈值并不是特别好,一些更好的相对方法可以在这个问题的其他答案中找到,或者在C FAQ list中的question 14.5中找到。
另外,作为另一个经验法则,您几乎不应该使用float类型,而应该总是使用double类型,它的精度大约是float类型的两倍,并且会给您带来更少的麻烦。

rjjhvcjd

rjjhvcjd3#

若要比较浮点值,应将相等性与给定的容差进行比较。除非已知数字的小数位数,否则将容差应用于数字之间差值的“规范化”表达式是很重要的。
例如,只有当ab接近1时,fabs(a-b) < tolerance才能给出所需的结果。但是,更好的替代方法是fabs(a/b)-1.0,它假定b不为0或非常接近0。在这种情况下,我假定操作数不为零(或接近零),因此解决方案如下所示:

#include <stdbool.h>
#include <math.h>

bool IsRightTriangle( float x, float y, float  z)
 {
    float tolerance = 0.0001;
    int result;
    
    return (fabs((x*x + y*y) / (z*z) - 1.0) < tolerance ||
        fabs((x*x + z*z) / (y*y) - 1.0) < tolerance ||
        fabs((y*y + z*z) / (x*x) - 1.0) < tolerance);
}

相关问题