如何有效地确保十进制值至少有N个小数位

Joe*_*Joe 4 .net c# language-specifications

我想在进行算术运算之前有效地确保十进制值至少具有N(在下面的示例中为3)位置.

显然,我可以用"0.000######....#"解析格式化,但效率相对较低,而且我正在寻找避免转换为字符串/从字符串转换的解决方案.

我尝试过以下解决方案:

decimal d = 1.23M;
d = d + 1.000M - 1;
Console.WriteLine("Result = " + d.ToString()); // 1.230
Run Code Online (Sandbox Code Playgroud)

这似乎适用于所有值<= Decimal.MaxValue - 1在使用Visual Studio 2015在Debug和Release版本中编译时.

但我怀疑编译器可能会优化(1.000 - 1).C#规范中有什么可以保证它始终有效吗?

或者是否有更好的解决方案,例如使用Decimal.GetBits

UPDATE

继Jon Skeet的回答后,我之前尝试过添加0.000M,但这对dotnetfiddle不起作用.所以我很惊讶地看到它Decimal.Add(d, 0.000M)确实有效. 这是一个dotnetfiddle比较d + 000Mdecimal.Add(d,0.000M):dotnetfiddle的结果不同,但使用Visual Studio 2015编译相同的代码时相同:

decimal d = 1.23M;
decimal r1 = decimal.Add(d, 0.000M);
decimal r2 = d + 0.000M;
Console.WriteLine("Result1 = " + r1.ToString());  // 1.230 
Console.WriteLine("Result2 = " + r2.ToString());  // 1.23 on dotnetfiddle
Run Code Online (Sandbox Code Playgroud)

所以至少有一些行为似乎依赖于编译器,这并不令人放心.

Jon*_*eet 6

如果您对编译器将优化运算符感到紧张(尽管我怀疑它会这样做),您可以直接调用该Add方法.请注意,您不需要添加然后减去 - 您只需添加0.000m.例如:

public static decimal EnsureThreeDecimalPlaces(decimal input) =>
    decimal.Add(input, 0.000m);
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常 - 如果你对编译器将对常量做什么感到紧张,你可以将这些位保留在一个数组中,只转换一次:

private static readonly decimal ZeroWithThreeDecimals =
    new decimal(new[] { 0, 0, 0, 196608 }); // 0.000m

public static decimal EnsureThreeDecimalPlaces(decimal input) =>
    decimal.Add(input, ZeroWithThreeDecimals);
Run Code Online (Sandbox Code Playgroud)

我认为这有点超过顶部 - 特别是如果你有好的单元测试.(如果你对你将要部署的编译代码进行测试,那么编译器之后就无法进入 - 我会非常惊讶地看到JIT介入此处.)