前几天我想到了这个。如果我们要将double
转换为int
保留Math.Floor
行为并且不担心溢出,为什么我们不正常投射它们并进行简单检查以获得与{{{{{ 1}}?
我继续用C#编写了这个方法:
Math.Floor
根据我的测试,public int TweakedCast(double num)
{
int ret = (int)num;
if (ret > num)
ret--;
return ret;
}
最多只有一半时间TweakedCast(num)
。
我有很多问题
这是一种可行的方式来(int)Math.Floor(num)
到double
演员而不用担心溢出吗?
对于所有数字,结果是否相同(即在两种方法中),即使是int
,NaN
和PositiveInfinity
?
使用NegativeInfinity
会有什么缺点吗?
为什么TweakedCast
最多占用一半的时间?是因为TweakedCast
是为双打而设计的吗?
我还想知道在Java中使用它时这段代码是否也会这样做,因为我没有正确的设置来进行测试。
答案 0 :(得分:0)
由于没有人得到答案,我测试了一下并得到了这些结果。
我制作了这个基准测试程序,看看结果是否总是一样的:
class Program
{
// all the code is unchecked, overflow is not important.
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
Random rand = new Random();
// Check random numbers (positive and negative) and see if they are the same on both function.
for (int i = 0; i < 5; i++)
{
double num = (rand.NextDouble() + rand.Next(10000)) * (rand.NextDouble() >= 0.5 ? 1 : -1);
Console.WriteLine("TweakedCast({0}) = {1}", num, TweakedCast(num));
Console.WriteLine("Math.Floor({0}) = {1}", num, Floor(num));
Console.WriteLine();
}
Console.WriteLine("TweakedCast({0}) = {1}", double.PositiveInfinity, TweakedCast(double.PositiveInfinity));
Console.WriteLine("Math.Floor({0}) = {1}", double.PositiveInfinity, Floor(double.PositiveInfinity));
Console.WriteLine();
Console.WriteLine("TweakedCast({0}) = {1}", double.NegativeInfinity, TweakedCast(double.NegativeInfinity));
Console.WriteLine("Math.Floor({0}) = {1}", double.NegativeInfinity, Floor(double.NegativeInfinity));
Console.WriteLine();
Console.WriteLine("TweakedCast({0}) = {1}", double.NaN, TweakedCast(double.NaN));
Console.WriteLine("Math.Floor({0}) = {1}", double.NaN, Floor(double.NaN));
Console.WriteLine();
double a = rand.NextDouble() + rand.Next(10000);
double b = -(rand.NextDouble() + rand.Next(10000));
Console.WriteLine("a: {0}, b: {1}", a, b);
Console.WriteLine("After 25 million iteration of both a and b on both methods, the result is:");
sw.Start();
for (int i = 0; i < 50000000; i++)
{
TweakedCast(a);
TweakedCast(b);
}
sw.Stop();
Console.WriteLine("TweakedCast time: {0}", sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 0; i < 50000000; i++)
{
Floor(a);
Floor(b);
}
sw.Stop();
Console.WriteLine("Math.Floor time: {0}", sw.ElapsedMilliseconds);
Console.ReadKey();
}
static int TweakedCast(double num)
{
int ret = (int)num;
if (ret > num)
ret--;
return ret;
}
static int Floor(double num)
{
return (int)Math.Floor(num);
}
}
<强>结果:强>
TweakedCast(-7668.35019480127) = -7669
Math.Floor(-7668.35019480127) = -7669
TweakedCast(-3737.06628523304) = -3738
Math.Floor(-3737.06628523304) = -3738
TweakedCast(-8627.20293022795) = -8628
Math.Floor(-8627.20293022795) = -8628
TweakedCast(9332.33679385313) = 9332
Math.Floor(9332.33679385313) = 9332
TweakedCast(-6910.65257059767) = -6911
Math.Floor(-6910.65257059767) = -6911
TweakedCast(Infinity) = -2147483648
Math.Floor(Infinity) = -2147483648
TweakedCast(-Infinity) = 2147483647
Math.Floor(-Infinity) = -2147483648
TweakedCast(NaN) = -2147483648
Math.Floor(NaN) = -2147483648
a: 9772.35618077747, b: -945.045879946577
After 25 million iteration of both a and b on both methods, the result is:
TweakedCast time: 2326
Math.Floor time: 4317
回答我的问题:
1- TweakedCast
是一种可行的方法,只要double
位于int.MinValue
和int.MaxValue
的边界内,就可以将整数作为整数。
2-对于几乎所有值,Math.Floor
和TweakedCast
的结果都相同。唯一的例外是double.NegativeInfinity
,它会在int.MaxValue
中以TweakedCast
和int.MinValue
中的Math.Floor
返回,这很可能是因为{Math.Floor
所做的检查1}}。
3-我发现的唯一不足之处在于,它仅适用于int.MinValue
和int.MaxValue
之间以及前一个回答中提及double.NegativeInfinity
的事实。
4-我对此没有明确的答案,但我的猜测是使用的算法不同,Math.Floor
开头的检查也可能产生很小的影响。此外,double
的大小是int
的两倍,但这也最不可能生效。
注意:我搜索了一个用Java制作的流行视频游戏的代码,他们有一个实用程序类可以实现更快的数学运算,并且使用铸造的地板方法完全相同简单的检查。这证明TweakedCast
可以完美地用于java。