为什么Math.Round / Floor / Ceiling不返回long或int?

时间:2022-09-06 08:12:05

Every time I use Math.Round/Floor/Ceiling I always cast to int (or perhaps long if necessary). Why exactly do they return double if it's always returning an integer.

每次我使用Math.Round / Floor / Ceiling时我总是转换为int(或者如果需要可能很长)。如果它总是返回一个整数,为什么它们会返回double。

4 个解决方案

#1


28  

The result might not fit into an int (or a long). The range of a double is much greater.

结果可能不适合int(或long)。双倍的范围要大得多。

Approximate range of double: ±5.0 × 10−324 to ±1.7 × 10308

双倍的近似范围:±5.0×10-324至±1.7×10308

(Source)

(资源)

#2


8  

I agree with Mark's answer that the result might not fit in a long, but you might wonder: what if C# had a much longer long type? Well, here's what happens in Python with it's arbitary-length integers:

我同意Mark的回答,结果可能不适合很长时间,但你可能想知道:如果C#有更长的类型怎么办?好吧,这是Python中使用它的任意长度整数所发生的事情:

>>> round(1.23e45)
1229999999999999973814869011019624571608236032

Most of the digits are "noise" from the floating-point rounding error. Perhaps part of the motivation for Round/Floor/Ceiling returning double in C# was to avoid the illusion of false precision.

大多数数字是来自浮点舍入误差的“噪声”。圆形/落地/天花板在C#中返回双倍的动机的一部分可能是为了避免错误精确的错觉。

An alternative explanation is that the .NET Math module uses code written in C, in which floor and ceil return floating-point types.

另一种解释是.NET Math模块使用用C编写的代码,其中floor和ceil返回浮点类型。

#3


2  

Range arguments aside, none of these answers addresses what, to me, is a fundamental problem with returning a floating point number when you really want an exact integer. It seems to me that the calculated floating point number could be less than or greater than the desired integer by a small round off error, so the cast operation could create an off by one error. I would think that, instead of casting, you need to apply an integer (not double) round-nearest function to the double result of floor(). Or else write your own code. The C library versions of floor() and ceil() are very slow anyway.

除了范围参数之外,这些答案都没有解决当我真正想要一个精确整数时返回浮点数的基本问题。在我看来,计算的浮点数可能小于或大于所需的整数一个小的舍入误差,因此转换操作可能会产生一个错误。我认为,你需要将一个整数(不是双倍)舍入函数应用于floor()的double结果,而不是强制转换。或者编写自己的代码。无论如何,floor()和ceil()的C库版本都非常慢。

Is this true, or am I missing something? There is something about an exact representation of integers in an IEEE floating point standard, but I am not sure whether or not this makes the cast safe.

这是真的,还是我错过了什么?在IEEE浮点标准中有一些关于整数的精确表示,但我不确定这是否使得转换安全。

I would rather have range checking in the function (if it is needed to avoid overflow) and return a long. For my own private code, I can skip the range checking. I have been doing this:

我宁愿在函数中进行范围检查(如果需要避免溢出)并返回long。对于我自己的私人代码,我可以跳过范围检查。我一直这样做:

long int_floor(double x)
{
    double remainder;
    long truncate;
    truncate = (long) x;        // rounds down if + x, up if negative x
    remainder = x - truncate;   // normally + for + x, - for - x
    //....Adjust down (toward -infinity) for negative x, negative remainder
    if (remainder < 0 && x < 0)
        return truncate - 1;
    else
        return truncate;
}

Counterparts exist for ceil() and round() with different considerations for negative and positive numbers.

对于ceil()和round()存在对应部分,对负数和正数有不同的考虑。

#4


-2  

There is no reason given on the docs that I could find. My best guess is that if you are working with doubles, chances are you would want any operations on doubles to return a double. Rounding it to cast to an int was deemed by the language designer less common then rounding and keeping as a double.

对于我能找到的文档没有任何理由。我最好的猜测是,如果你正在使用双打,很可能你会想要对双打进行任何操作来返回双精度数。对它进行舍入以转换为int被语言设计者认为不那么常见,然后舍入并保持为双精度。

You could write your own method that cast it to an int for you in about 2 lines of code, and much less work than posting a question on stack overflow...

您可以编写自己的方法,在大约2行代码中将它转换为int,并且比在堆栈溢出上发布问题要少得多...

#1


28  

The result might not fit into an int (or a long). The range of a double is much greater.

结果可能不适合int(或long)。双倍的范围要大得多。

Approximate range of double: ±5.0 × 10−324 to ±1.7 × 10308

双倍的近似范围:±5.0×10-324至±1.7×10308

(Source)

(资源)

#2


8  

I agree with Mark's answer that the result might not fit in a long, but you might wonder: what if C# had a much longer long type? Well, here's what happens in Python with it's arbitary-length integers:

我同意Mark的回答,结果可能不适合很长时间,但你可能想知道:如果C#有更长的类型怎么办?好吧,这是Python中使用它的任意长度整数所发生的事情:

>>> round(1.23e45)
1229999999999999973814869011019624571608236032

Most of the digits are "noise" from the floating-point rounding error. Perhaps part of the motivation for Round/Floor/Ceiling returning double in C# was to avoid the illusion of false precision.

大多数数字是来自浮点舍入误差的“噪声”。圆形/落地/天花板在C#中返回双倍的动机的一部分可能是为了避免错误精确的错觉。

An alternative explanation is that the .NET Math module uses code written in C, in which floor and ceil return floating-point types.

另一种解释是.NET Math模块使用用C编写的代码,其中floor和ceil返回浮点类型。

#3


2  

Range arguments aside, none of these answers addresses what, to me, is a fundamental problem with returning a floating point number when you really want an exact integer. It seems to me that the calculated floating point number could be less than or greater than the desired integer by a small round off error, so the cast operation could create an off by one error. I would think that, instead of casting, you need to apply an integer (not double) round-nearest function to the double result of floor(). Or else write your own code. The C library versions of floor() and ceil() are very slow anyway.

除了范围参数之外,这些答案都没有解决当我真正想要一个精确整数时返回浮点数的基本问题。在我看来,计算的浮点数可能小于或大于所需的整数一个小的舍入误差,因此转换操作可能会产生一个错误。我认为,你需要将一个整数(不是双倍)舍入函数应用于floor()的double结果,而不是强制转换。或者编写自己的代码。无论如何,floor()和ceil()的C库版本都非常慢。

Is this true, or am I missing something? There is something about an exact representation of integers in an IEEE floating point standard, but I am not sure whether or not this makes the cast safe.

这是真的,还是我错过了什么?在IEEE浮点标准中有一些关于整数的精确表示,但我不确定这是否使得转换安全。

I would rather have range checking in the function (if it is needed to avoid overflow) and return a long. For my own private code, I can skip the range checking. I have been doing this:

我宁愿在函数中进行范围检查(如果需要避免溢出)并返回long。对于我自己的私人代码,我可以跳过范围检查。我一直这样做:

long int_floor(double x)
{
    double remainder;
    long truncate;
    truncate = (long) x;        // rounds down if + x, up if negative x
    remainder = x - truncate;   // normally + for + x, - for - x
    //....Adjust down (toward -infinity) for negative x, negative remainder
    if (remainder < 0 && x < 0)
        return truncate - 1;
    else
        return truncate;
}

Counterparts exist for ceil() and round() with different considerations for negative and positive numbers.

对于ceil()和round()存在对应部分,对负数和正数有不同的考虑。

#4


-2  

There is no reason given on the docs that I could find. My best guess is that if you are working with doubles, chances are you would want any operations on doubles to return a double. Rounding it to cast to an int was deemed by the language designer less common then rounding and keeping as a double.

对于我能找到的文档没有任何理由。我最好的猜测是,如果你正在使用双打,很可能你会想要对双打进行任何操作来返回双精度数。对它进行舍入以转换为int被语言设计者认为不那么常见,然后舍入并保持为双精度。

You could write your own method that cast it to an int for you in about 2 lines of code, and much less work than posting a question on stack overflow...

您可以编写自己的方法,在大约2行代码中将它转换为int,并且比在堆栈溢出上发布问题要少得多...