最近我发现C#的运算符%
适用于double。尝试了一些事情,毕竟想出了这个测试:
class Program
{
static void test(double a, double b)
{
if (a % b != a - b * Math.Truncate(a / b))
{
Console.WriteLine(a + ", " + b);
}
}
static void Main(string[] args)
{
test(2.5, 7);
test(-6.7, -3);
test(8.7, 4);
//...
}
}
此测试中的所有内容都有效。
a % b
是否始终等同于a - b*Math.Round(a/b)
?如果没有,请向我解释这个运营商是如何运作的。
答案 0 :(得分:6)
模数运算符以与整数相同的方式处理浮点值。所以请考虑一个简单的例子:
4.5 % 2.1
现在,4.5 / 2.1约等于2.142857
因此,除法的整数部分是2.从4.5减去2 * 2.1并且你得到了剩余的0.3。
当然,此过程受浮点表示问题的影响,因此要注意 - 您可能会看到意外的结果。例如,请参阅Stack Overflow上的此问题:Floating Point Arithmetic - Modulo Operator on Double Type
%b是否总是等于a - b * Math.Round(a / b)?
不,不是。这是一个简单的反例:
static double f(double a, double b)
{
return a - b * Math.Round(a / b);
}
static void Main(string[] args)
{
Console.WriteLine(1.9 % 1.0);
Console.WriteLine(f(1.9, 1.0));
Console.ReadLine();
}
关于如何指定模数运算符的精确细节,您需要参考C#规范 - earlNameless's answer为您提供指向它的链接。
据我了解,a % b
与a - b*Math.Truncate(a/b)
基本等效,模浮点精度。
答案 1 :(得分:4)
来自C# Language Specifications第200页:
浮点余数:
float operator %(float x, float y);
double operator %(double x, double y);
下表列出了非零有限值,零,无穷大和NaN的所有可能组合的结果。在表中,x和y是正有限值。 z是x%y的结果,计算为x - n * y,四舍五入到最接近的可表示值,其中n是小于或等于x / y的最大整数。这种计算余数的方法类似于用于整数操作数的方法,但不同于IEC 60559定义(其中n是最接近x / y的整数)。
答案 2 :(得分:2)
答案 3 :(得分:0)
使用短语“ modulo float point c#”进行搜索会在Stack Overflow中显示很多条目,其中大多数很好地说明了浮点精度如何使事情变得复杂。我没有发现任何建议来解决这种简单实用的方法。我出于自己的目的想到的是以下模函数:
public static double modulo( double a, double b, double num_sig_digits = 14 )
{
double int_closest_to_ratio
, abs_val_of_residue
;
if ( double.IsNaN( a )
|| double.IsNaN( b )
|| 0 == b
)
{
throw new Exception( "function modulo called with a or b == NaN or b == 0" );
}
if ( b == Math.Floor( b ) )
{
return (a % b);
}
else
{
int_closest_to_ratio = Math.Round( a / b );
abs_val_of_residue = Math.Abs( a - int_closest_to_ratio * b );
if ( abs_val_of_residue < Math.Pow( 10.0, -num_sig_digits ) )
{
return 0.0;
}
else
{
return abs_val_of_residue * Math.Sign( a );
}
}
}
以下是一些示例结果:
modulo(0.5,0.1,17)= 0
modulo(0.5,-0.1,16)= 0
modulo(-0.5,0.1,15)= 0
modulo(-0.5,-0.1,14)= 0
modulo(0.52,0.1,16)= 0.02
modulo(0.53,-0.1,15)= 0.03
modulo(-0.54,0.1,14)= -0.04
modulo(-0.55,-0.1,13)= -0.05
modulo(2.5,1.01,17)= 0.48
modulo(2.5,-1.01,16)= 0.48
modulo(-2.5,1.01,15)= -0.48
modulo(-2.5,-1.01,14)= -0.48
模(0.599999999999977,0.1%,16)= 2.35367281220533E-14
模(0.599999999999977,0.1%,15)= 2.35367281220533E-14
模(0.599999999999977,0.1%,14)= 2.35367281220533E-14
取模(0.599999999999977,0.1,13)= 0
取模(0.599999999999977,0.1,12)= 0