如何检查双x是否可以被C中的另一个双y整除?对于整数,我只使用模数,但是用双精度执行它的正确/最佳方法是什么?
我知道浮点数带有不精确性,但我从标准输入得到了双倍。也许我不应该直接扫描它,而是将其作为两个整数扫描,但是从那时起我会去哪里?
答案 0 :(得分:17)
标准标题math.h
定义了以下功能:
double fmod(double x, double y);
float fmodf(float x, float y);
long double fmodl(long double x, long double y);
这些函数返回x
的余数除以y
的结果。结果与x
的结果相同。您可以r = fmod(x, y);
使用double
个数字x
和y
,并检查是否r == 0
。如果您不想测试完全可分性但添加一些容差,那么您可以检查r
是否“足够接近”0或y
(感谢caf)。< / p>
fmodf()
和fmodl()
是C99中的新内容。
编辑:C99还定义了一个单独的remainder(double x, double y)
函数,它返回x/y
的余数。来自http://docs.sun.com/source/806-3568/ncg_lib.html:
remainder(x,y)
是IEEE标准754-1985中指定的操作。remainder(x,y)
和fmod(x,y)
之间的区别在于remainder(x,y)
返回的结果符号可能与x
或y
的符号不一致,而{ {1}}始终返回符号与fmod(x,y)
一致的结果。这两个函数都返回精确的结果,并且不会生成不精确的异常。
...
当
x
≠0时,无论采用数学关系y
的舍入模式,都会定义余数r = x REM y
,其中r = x - ny
是最接近精确值的整数n
;只要x/y
,那么| n - x/y | = 1/2
就是偶数。因此,其余部分总是精确的。如果n
,其标志应为r = 0
的标志。该定义适用于所有实现。
(x
或fmod()
应该适合您。)
答案 1 :(得分:7)
fmod()系列函数会产生可怕的结果。假设您要确定42是否可被0.4整除。这是105次。然而,fmod进行除法并得到像104.99999这样的结果,然后向下舍入到104,导致余数为0.399999,这给出了假阴性结果。然而,remainderl()似乎有效。甚至0.4本身也表示不精确浮点。
对于那些没有理解“可分割”概念的人来说,它与结果是偶数无关 - 你的语源可能会倒退。偶数是那些可被2整除的数。并且可分解的概念对于非整数是完全有效的。均匀可分,意味着无论被除数还是除数,除法的结果都是整数。一个示例应用是如果您有一个带有3mm螺距导螺杆的金属车床并且正在切割0.4mm螺距螺栓。 3毫米的14个螺纹与0.4毫米的105个螺纹对齐。可分性计算用于指示车床的各个运动部件再次同步,以便您可以重新接通下一个切割通道。另一个例子是已经转换为公制的英制测量。 50.8毫米(2英寸)可被25.4毫米(1英寸)整除。即使没有度量转换,维度通常也是非整数,但可分性通常是一个问题:0.5“可被0.1”,0.125“和0.250”整除。将浮点数(例如0.375“)转换为小数表示(3/8”)是对非整数的另一种可分性应用。
此示例函数中的两个备选计算为数百个不同的数字对提供相同的结果。但是,用floorl()替换带有fmodl()或roundl()的remainderl()会产生大量无效结果。我最初使用0.001的模糊。实际计算误差通常为1E-15阶,因此可以使用较小的模糊。但是,将结果与0.0进行比较将得出假阴性结果。如果你使用非常小的数字,你可能想用你的分母来表达你的模糊。 divisible(42,0.4)和divisible(41,0.4)应该给出与divisible(0.000000042,0.0000000004)和divisible(0.000000041,0.0000000004)相同的结果。 I.E.是42nm和41nm可被0.4nm整除?使用此处给出的函数版本,它们可以。固定的模糊,他们不一定。但是,可分(42,0.0000000004)仍然给出假阴性(误差为1.53003e-15,大于4E-19的模糊),因此比较相差9个数量级的数字是不可靠的。 IEEE浮点有其局限性。注意我使用长双精度计算来最小化计算和表示错误。此功能未使用负数进行测试。
int divisible(long double a, long double b)
{
int result;
#if 1
if(fabsl(((roundl(a/b)*b)- a)) <= (1E-9*b) ) {
result=TRUE;
} else {
result=FALSE;
}
#else
if( fabsl(remainderl(a,b)) <= (1E-9*b ) ){
result=TRUE;
} else {
result=FALSE;
}
#endif
// printf("divisible(%Lg, %Lg): %Lg, %Lg,%d\n", a, b, roundl(a/b), fabsl(((roundl(a/b)*b)-a)), result);
return(result);
}
答案 2 :(得分:3)
我不确定你要做什么,但我在math.h中使用了fmod()音频合成代码,我需要我的参数是浮点数或双精度数,我需要得到一个模数。
答案 3 :(得分:3)
如果你想要绝对精确,你可以使用定点数学。也就是说,用int来做所有事情,但是(在你的情况下)它们实际代表的价值为10的一些权力。
假设用户输入123.45和6789.1。首先,您要确保您具有相同的小数位数,因此将尾随零添加到具有较少小数位的零。这给了我们123.45和6789.10(现在都有2位小数)。现在只需删除小数点,得到12345和678910.如果一个均分为另一个,那就是你的答案。
这是有效的,因为删除小数点会将两者相乘相同的常量(上例中为100)。 (x * 100) / (y * 100) == x / y
要注意的一些事项:如果您将整数部分和小数部分读作整数,请注意不要在小数部分丢失前导零。 (例如:0.1和0.0001不是同一个数字!)另外,如果有足够的小数位,你可以溢出。你可能想要至少使用很长时间。
你也可以用双打进行计算,但它的精确度会降低。要这样做,进行除法,然后比较结果和舍入结果之间的差异。如果在一些小的容差范围内,则它会均匀分配。
答案 4 :(得分:2)
lol - 第3行修复:)
答案 5 :(得分:2)
如何检查双x是否可以被C中的另一个双y均匀分割?对于整数,我只使用模数,但是用双精度执行它的正确/最佳方法是什么?
您将包含并链接到数学库:
#include <math.h>
然后你会调用浮点模数函数fmod:
if (fmod(5.0, 2.5) == 0.0)
// evenly divisible
else
// not evenly divisible
根据您的需要,您可能希望将fmod的结果与较小的值而不是0.0进行比较。
答案 6 :(得分:-4)
“偶数”的概念仅针对整数定义。你不能将它应用于双打;它没有数学意义。来自Wikipedia:
偶数是一个整数 “均匀分割”为2,即 可以被2除尽。
我建议您通过应用您决定的任何方法(舍入,截断)将双打转换为整数,然后按照您的建议使用模数。