我被问到以下问题,我不知道如何回答。我想知道是否有人可以提供帮助:
使用 C#,而不使用任何数学函数(不允许使用 Round() 和 Truncate())取以下双精度 3.009784654 并将其四舍五入到小数点后 4 位。
这是为了面试,不是为了课堂项目或家庭作业。面试官似乎是想让我用mod,但我还是想不出怎么做。
谢谢!
截断(因为未指定舍入规则):乘以 1e4,强制转换为 int,除以 1e4。
这是一个糟糕的面试问题,因为给定预期的工具,该任务通常是不可能的,因为大多数正确的结果都无法表示。也就是说,普通的浮点类型不能准确地表示正确的数学结果 3.0098。所以不可能计算并返回正确的答案。您将不得不使用一些替代机制,例如以不同类型返回值(缩放为整数、字符串、十进制浮点格式等)。
我怀疑面试官可能期待的答案是评估 (int)(x*10000+.5)*.0001。这会缩放该值,以便所需的结果是整数(舍入量 .0001,缩放为 1),添加 0.5,截断为整数,并反转缩放。添加 0.5 和截断的组合几乎等同于舍入,除了它要求 x 为正数、从零开始舍入关系以及存在范围/域问题。可以根据情况和所需的行为对这些进行调整。而且,当然,由于无法表示准确的结果,答案通常略有不正确。
一个更有趣的答案是评估 (x*10000+0x1p52-0x1p52)*.0001。这会缩放值,使用当前浮点舍入模式将其舍入为整数,然后撤消缩放。进行舍入是因为常见的 double 类型在其有效数中有 53 位,因此,当高位的值为 0x1p52 (2 52 ) 时,低位的值为 0x1p0 (2 0,也称为 1)。为了产生加 0x1p52 的结果,必须对有效位进行四舍五入,这是在浮点硬件中自动完成的。然后减去 0x1p52 删除添加的数字,留下四舍五入的值。和以前一样,范围/域有一些警告,并确保编译器执行双精度算术而不是更多,并且可以进行调整。但是,在某些硬件上它比转换为整数并返回要快。
使用 fmod 或字符串转换的性能更差,因为它们需要除法,这在大多数常见处理器上很慢。
乘以 10^numberOfDigitsAfterComma,转换为 int,然后返回浮点数并除以 10^...
double x = 3.009784654;
x = ((double)((int)(x * 10000))) / 10000;
如果你真的需要mod,你可以这样做:
double number = 3.009784654;
double truncatedNumber = number - number % 0.0001;
使用 mod 的答案:
double d = 1.23456789;
int digitsToKeep = 2;
double divisor = Math.Pow(10, digitsToKeep * -1);
double rounded = d - (d % divisor);
如果需要,这也会将数字向上取整。
public static double Round(double number, int digits)
{
for (int i = 0; i < digits; i++)
number *= 10;
int whole = (int)number;
double fraction = number - whole;
if (fraction >= 0.5)
whole++;
number = whole;
for (int i = 0; i < digits; i++)
number /= 10.0;
return number;
}