将数字截断到指定的小数位数
本文关键字:小数 数字 | 更新日期: 2023-09-27 18:22:21
我需要将一个数字截断到小数点后2位,这基本上意味着切掉多余的数字。
例如:
2.919 -> 2.91
2.91111 -> 2.91
为什么?这就是SQL server在存储特别精确。例如,如果一列是Decimal(8,2),并且您尝试插入/更新编号9.1234,则3和4将被截断。
我需要在c#代码中做完全相同的事情。
我能想到的唯一可能的方法是:
仅使用字符串格式器"打印"出来两位小数,然后将其转换为十进制,例如:
decimal tooManyDigits = 2.1345 decimal ShorterDigits = Convert.ToDecimal(tooManyDigits.ToString("0.##")); // ShorterDigits is now 2.13
我对此不满意,因为它涉及到一个to字符串,然后另一个字符串到十进制的转换似乎有点疯狂。
使用Math.Ttruncate(只接受整数),所以我可以将它乘以100,截断它,然后除以100。例如:
decimal tooLongDecimal = 2.1235; tooLongDecimal = Math.Truncate(tooLongDecimal * 100) / 100;
我对此也不满意,因为如果tooLongDecimal为0,我会得到一个被0除的错误。
当然还有更好更简单的方法!有什么建议吗?
您自己已经回答了这个问题;你好像误解了零除法的意思。做到这一点的正确方法是相乘、截断,然后进行devide,如下所示:
decimal TruncateTo100ths(decimal d)
{
return Math.Truncate(d* 100) / 100;
}
TruncateTo100ths(0m); // 0
TruncateTo100ths(2.919m); // 2.91
TruncateTo100ths(2.91111m); // 2.91
TruncateTo100ths(2.1345m); // 2.13
这里没有除以零,只有除以100,这是完全安全的。
以前提供的数学解决方案很容易被大量数字和/或小数位数溢出。考虑以下扩展方法:
public static decimal TruncateDecimal(this decimal d, int decimals)
{
if (decimals < 0)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals > 28)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals == 0)
return Math.Truncate(d);
else
{
decimal integerPart = Math.Truncate(d);
decimal scalingFactor = d - integerPart;
decimal multiplier = (decimal) Math.Pow(10, decimals);
scalingFactor = Math.Truncate(scalingFactor * multiplier) / multiplier;
return integerPart + scalingFactor;
}
}
用法:
decimal value = 18446744073709551615.262626263m;
value = value.TruncateDecimal(6); // Result: 18446744073709551615.262626
我同意p.s.w.g.我也有类似的要求,下面是我的经验和一个更通用的截断函数。
http://snathani.blogspot.com/2014/05/truncating-number-to-specificnumber-of.html
public static decimal Truncate(decimal value, int decimals)
{
decimal factor = (decimal)Math.Pow(10, decimals);
decimal result = Math.Truncate(factor * value) / factor;
return result;
}
使用decimal.ToString('0.##')
也强制舍入:
1.119M.ToString("0.##") // -> 1.12
(是的,可能应该是一个注释,但很难像这样格式化。)
public static decimal Rounding(decimal val, int precision)
{
decimal res = Trancating(val, precision + 1);
return Math.Round(res, precision, MidpointRounding.AwayFromZero);
}
public static decimal Trancating(decimal val,int precision)
{
if (val.ToString().Contains("."))
{
string valstr = val.ToString();
string[] valArr = valstr.Split('.');
if(valArr[1].Length < precision)
{
int NoOfZeroNeedToAdd = precision - valArr[1].Length;
for (int i = 1; i <= NoOfZeroNeedToAdd; i++)
{
valstr = string.Concat(valstr, "0");
}
}
if(valArr[1].Length > precision)
{
valstr = valArr[0] +"."+ valArr[1].Substring(0, precision);
}
return Convert.ToDecimal(valstr);
}
else
{
string valstr=val.ToString();
for(int i = 0; i <= precision; i++)
{
if (i == 1)
valstr = string.Concat(valstr, ".0");
if(i>1)
valstr = string.Concat(valstr, "0");
}
return Convert.ToDecimal(valstr);
}
}