在 C# 中,如何在没有舍入的情况下修复小数类型的点后位数。
例如:十进制坐标 = 47.483749999999816;(地理坐标的一部分)
我只需要在点后保留 6 位数:47.483749
你可能会使用
decimal truncated = Math.Truncate(coords * 1000000m) / 1000000m;
或许
decimal truncated = Math.Truncate(coords / 0.000001m) * 0.000001m;
在这两个中,我开始更喜欢后者。该数字0.000001m
在内部表示为尾数1
和 scale 6
,因此除以它实际上只是将小数点移动了六位。
最后乘以的方法0.000001m
往往会给出小数点后正好六位数的结果,即使必要时尾随零也是如此。例如coords = 1.23m
会导致truncated
被1.230000m
。
如评论中所述,上述技术都会导致OverflowException
ifcoords
太大(超过 百万分之一decimal.MaxValue
)。
为了完整起见,这里有几个其他的解决方案:
decimal truncated = coords - coords % 0.000001m;
这似乎工作正常。虽然尾随零的数量并不总是正确的,但我相信它会给出相同的结果。运算符==
(或decimal.Equals
)。
最后,您可以使用:
decimal truncated = Math.Round(coords - 0.0000005m, 6, MidpointRounding.AwayFromZero);
但这仅适用于非负数coords
。
如果您真正需要的是格式化string
,请调用ToString
重载 on truncated
。但请注意,正如我所指出的,尾随零。如果你使用.ToString("F6")
,应该总是有六位小数。
当然,您也可以使用字符串操作进行截断。它会是这样的:
string coordsString = coords.ToString(CultureInfo.InvariantCulture);
int idxOfPoint = coordsString.IndexOf(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
if (idxOfPoint != -1 && coordsString.Length > 6 + 1 + idxOfPoint)
coordsString = coordsString.Remove(6 + 1 + idxOfPoint);
// coordsString is now truncated correctly.
// If you need a decimal, use decimal.Parse(coordsString)
非常棘手,不建议,但我真的不知道你在寻找什么解决方案(因为你正在避免rounding
):
double k = 47.483749999999816;
k = double.Parse(Regex.Replace(k.ToString(), @"(\d+\.\d{6})(.\d+)", x => x.Groups[1].Value));
Console.WriteLine(k);
打印
47.483749
您可以使用
decimal.Round( 47.483749999999816, 6)