检查双倍是否可以被C中的另一个双倍整除?

如何检查双x是否可以被C中的另一个双y整除? 使用整数我只会使用模数,但是用双精度执行它的正确/最佳方法是什么?

我知道浮点数带有不精确性,但我从标准输入得到了双倍。 也许我不应该直接扫描它,而是将其作为两个整数扫描,但是从那时起我会去哪里?

标准头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); 对于doublexy ,并检查r == 0 。 如果你不想测试精确的可分性但增加一些容差,那么你可以检查r是否“足够接近”0或y (感谢caf)。

fmodf()fmodl()是C99中的新function。

编辑 :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)返回的结果的符号可能与xy的符号fmod(x,y) ,而fmod(x,y)始终返回符号与x一致的结果。 这两个函数都返回精确的结果,不会生成不精确的exception。

y ≠0时,无论舍入模式如何,通过数学关系r = x - ny定义余数r = x REM y ,其中n是最接近x/y的精确值的整数; 每当| n - x/y | = 1/2 | n - x/y | = 1/2 | n - x/y | = 1/2 ,则n是偶数。 因此,其余部分总是精确的。 如果r = 0 ,则其符号应为x符号。 该定义适用于所有实现。

fmod()remainder()应该适合你。)

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)相同的结果。 IE是42nm和41nm可被0.4nm整除? 使用此处给出的函数版本,它们可以。 固定的模糊,他们不一定。 但是,可分(42,0.0000000004)仍然给出假阴性(误差是1.53003e-15,大于4E-19的模糊),因此比较相差9个数量级的数字是不可靠的。 IEEE浮点有其局限性。 注意我使用长双精度计算来最小化计算和表示错误。 此function未使用负数进行测试。

 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); } 

如果你想要绝对精确,你可以使用定点数学。 也就是说,使用整数来做所有事情,但是(在你的情况下)它们实际代表的价值的10倍的整数。

假设用户输入123.45和6789.1。 首先,您要确保您具有相同的小数位数,因此将尾随零添加到具有较少小数位的零。 这给了我们123.45和6789.10(现在都有2位小数)。 现在只需删除小数点,得到12345和678910.如果一个均分为另一个,那就是你的答案。

这是有效的,因为删除小数点会将两者相乘相同的常量(上例中为100)。 (x * 100) / (y * 100) == x / y

有几点需要注意:如果你将整数部分和小数部分作为整数读取,请注意不要在小数部分丢失前导零。 (例如:0.1和0.0001不是相同的数字!)另外,如果有足够的小数位,你可以溢出。 你可能想要至少使用很长时间。

你也可以用双打进行计算,但它的精确度会降低。 要这样做,进行除法,然后比较结果和舍入结果之间的差异。 如果在一些小的公差范围内,则它均匀分配。

我不确定你要做什么,但我在math.h中使用了fmod()音频合成代码,我需要我的参数是浮点数或双精度数,我需要得到一个模数。

  1. 将它们作为双打扫描并将其称为x1和x2
  2. 找到x1 / x2正在使用除法并将其命名为x3
  3. 找到x1 – (x2 * x3)并查看该数字是否足够接近零 – 如果是,那么x1可被x2整除 – (显然在这里考虑负值的可能性)

大声笑 – 第3行固定:)

如何检查双x是否可以被C中的另一个双y均匀分割? 使用整数我只会使用模数,但是用双精度执行它的正确/最佳方法是什么?

您将包含并链接到数学库:

#include

然后你会调用浮点模数函数fmod :

 if (fmod(5.0, 2.5) == 0.0) // evenly divisible else // not evenly divisible 

您可能希望根据需要将fmod的结果与小值而不是0.0进行比较。

“偶数”的概念仅针对整数定义。 你不能将它应用于双打; 它没有数学意义。 来自维基百科 :

偶数是一个“可被2整除”的整数,即可被2整除而没有余数。

我建议你通过应用你决定的任何方法(舍入,截断)将你的双打转换为整数,然后按照你的建议使用模数。