如何将Math.Ciling结果转换为int

本文关键字:转换 int 结果 Ciling Math | 更新日期: 2023-09-27 18:20:01

Math.Ceiling返回double,因为double可能存储更大的数字。但是,如果我确信int类型能够存储结果,我应该如何转换?投(int) Math.Ceiling(...安全吗?

如何将Math.Ciling结果转换为int

如果您确信没有超出int的容量,那么进行应该是完全安全的

int myInt = (int)Math.Ceiling(...);

如果您不确定绑定,可以使用long而不是int

根据C++实践,我将使用以下内容。即使天花板返回99.99999…8或1.00000000…1 ,也能保证得到正确的结果

var result = (int)(Math.Ceiling(value) + 0.5);

如果你信任的实现,下面的代码也应该有效

var result = Convert.ToInt32(value);

如果一切都与速度有关,那么Int输入和输出的Math.Ciling就相当慢。最快的是内联表达式。2.4秒vs 33毫秒

警告:仅适用于正值valuedivisor

A)模量

这是我提出的一个,显然以前C/C++开发人员也发现过:

var ceilingResult = (value / divisor) + (value % divisor == 0 ? 0 : 1);

根据我自己的10M迭代基准,Math.Ciling大约需要2.4秒。在命名函数内部调用此表达式需要约380毫秒,将其作为直接内联表达式需要约33毫秒。

B)仅限简单算术

也可以考虑使用@mafu 的建议

var ceilingResult = (value + divisor - 1) / divisor;

请参阅此470次投票的C++答案以供参考和验证。而且https://stackoverflow.com/a/4175152/887092.

C)DivRem

当看到这个答案时,https://stackoverflow.com/a/14878734/887092,我注意到了提醒我有关DivRem CPU指令的评论。看见https://learn.microsoft.com/en-us/dotnet/api/system.math.divrem?view=netframework-4.8.Math.DivRem应该被解析为这样的CPU指令。

var quotient = Math.DivRem(value, divisor, out long remainder);
var ceilingResult = quotient + (remainder == 0 ? 0 : 1);

[我没有对此进行测试]。看见https://stackoverflow.com/a/924160/887092,对于潜在的边缘情况(使用负Int数)

对此可能会进行进一步的优化——也许是铸造。在该回答中,https://stackoverflow.com/a/924160/887092,使用了if条件语句-它们大致相同。


3:的性能

  • 模数:有两个添加的运算,但也有一个条件分支
  • 算术:在序列中有一些额外的数学运算
  • DivRem:建立在模数法的基础上。如果C#确实将Math.DivRem解析为一条CPU指令,这可能会更快。进一步的优化也是可能的

我不确定这两者在不同的体系结构上会如何表现。但现在你可以选择探索。


如果你想要Int输入和输出的Math.Floor,那就更容易了:

var floorResult = (value / divisor);

我会选择

int x = (int)Math.Ceiling(0.9); // 1

如果你不确定,你总是可以放一个If语句,检查你得到的数字是否更高,然后int.MaxValue

int oInt = Convert.ToInt32(Math.Ceiling(value));

由于Math.Ceiling返回double,并且您希望将其转换为int,因此请使用ConvertClass
示例:

double[] values= { Double.MinValue, -1.38e10, -1023.299, -12.98,
                   0, 9.113e-16, 103.919, 17834.191, Double.MaxValue };
int result;
foreach (double value in values)
{
   try {
      result = Convert.ToInt32(value);
      Console.WriteLine("Converted the {0} value '{1}' to the {2} value {3}.",
                        value.GetType().Name, value,
                        result.GetType().Name, result);
   }
   catch (OverflowException) {
      Console.WriteLine("{0} is outside the range of the Int32 type.", value);
   }   
}                                 
//    -1.79769313486232E+308 is outside the range of the Int32 type.
//    -13800000000 is outside the range of the Int16 type.
//    Converted the Double value '-1023.299' to the Int32 value -1023.
//    Converted the Double value '-12.98' to the Int32 value -13.
//    Converted the Double value '0' to the Int32 value 0.
//    Converted the Double value '9.113E-16' to the Int32 value 0.
//    Converted the Double value '103.919' to the Int32 value 104.
//    Converted the Double value '17834.191' to the Int32 value 17834.
//    1.79769313486232E+308 is outside the range of the Int32 type.