截断两个小数位而不舍入
假设我有一个3.4679的值,想要3.46,我怎样才能截断到两位小数,而不是四舍五入?
我已经尝试了以下但所有三个给我3.47:
void Main() { Console.Write(Math.Round(3.4679, 2,MidpointRounding.ToEven)); Console.Write(Math.Round(3.4679, 2,MidpointRounding.AwayFromZero)); Console.Write(Math.Round(3.4679, 2)); }
这返回3.46,但似乎肮脏一些如何:
void Main() { Console.Write(Math.Round(3.46799999999 -.005 , 2)); }
value = Math.Truncate(100 * value) / 100;
注意像这样的分数不能用浮点精确表示。
在C#中使用截断小数的真实世界中有一个完整的函数将会更有用。 这可以转换为十进制扩展方法很容易,如果你想要的话:
public decimal TruncateDecimal(decimal value, int precision) { decimal step = (decimal)Math.Pow(10, precision); decimal tmp = Math.Truncate(step * value); return tmp / step; }
如果你需要VB.NET试试这个:
Function TruncateDecimal(value As Decimal, precision As Integer) As Decimal Dim stepper As Decimal = Math.Pow(10, precision) Dim tmp As Decimal = Math.Truncate(stepper * value) Return tmp / stepper End Function
然后像这样使用它:
decimal result = TruncateDecimal(0.275, 2);
要么
Dim result As Decimal = TruncateDecimal(0.275, 2)
其他例子中的一个问题是在分割input值之前将其乘以数值。 在这里有一个边缘情况,你可以通过乘以第一个边缘情况来溢出小数点,但是我碰到过的东西。 分开处理小数部分比较安全,如下所示:
public static decimal TruncateDecimal(this decimal value, int decimalPlaces) { decimal integralValue = Math.Truncate(value); decimal fraction = value - integralValue; decimal factor = (decimal)Math.Pow(10, decimalPlaces); decimal truncatedFraction = Math.Truncate(fraction * factor) / factor; decimal result = integralValue + truncatedFraction; return result; }
使用模运算符:
var fourPlaces = 0.5485M; var twoPlaces = fourPlaces - (fourPlaces % 0.01M);
结果:0.54
我将离开十进制数的解决scheme。
这里小数点的一些解决scheme很容易溢出(如果我们传递一个非常大的十进制数,并且方法将会尝试乘以它)。
蒂姆·劳埃德的解决scheme是防止溢出,但不是太快。
以下解决scheme速度提高了约2倍,并且没有溢出问题:
public static class DecimalExtensions { public static decimal TruncateEx(this decimal value, int decimalPlaces) { if (decimalPlaces < 0) throw new ArgumentException("decimalPlaces must be greater than or equal to 0."); var modifier = Convert.ToDecimal(0.5 / Math.Pow(10, decimalPlaces)); return Math.Round(value >= 0 ? value - modifier : value + modifier, decimalPlaces); } } [Test] public void FastDecimalTruncateTest() { Assert.AreEqual(-1.12m, -1.129m. TruncateEx(2)); Assert.AreEqual(-1.12m, -1.120m. TruncateEx(2)); Assert.AreEqual(-1.12m, -1.125m. TruncateEx(2)); Assert.AreEqual(-1.12m, -1.1255m.TruncateEx(2)); Assert.AreEqual(-1.12m, -1.1254m.TruncateEx(2)); Assert.AreEqual(0m, 0.0001m.TruncateEx(3)); Assert.AreEqual(0m, -0.0001m.TruncateEx(3)); Assert.AreEqual(0m, -0.0000m.TruncateEx(3)); Assert.AreEqual(0m, 0.0000m.TruncateEx(3)); Assert.AreEqual(1.1m, 1.12m. TruncateEx(1)); Assert.AreEqual(1.1m, 1.15m. TruncateEx(1)); Assert.AreEqual(1.1m, 1.19m. TruncateEx(1)); Assert.AreEqual(1.1m, 1.111m. TruncateEx(1)); Assert.AreEqual(1.1m, 1.199m. TruncateEx(1)); Assert.AreEqual(1.2m, 1.2m. TruncateEx(1)); Assert.AreEqual(0.1m, 0.14m. TruncateEx(1)); Assert.AreEqual(0, -0.05m. TruncateEx(1)); Assert.AreEqual(0, -0.049m. TruncateEx(1)); Assert.AreEqual(0, -0.051m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.14m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.15m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.16m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.19m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.199m. TruncateEx(1)); Assert.AreEqual(-0.1m, -0.101m. TruncateEx(1)); Assert.AreEqual(0m, -0.099m. TruncateEx(1)); Assert.AreEqual(0m, -0.001m. TruncateEx(1)); Assert.AreEqual(1m, 1.99m. TruncateEx(0)); Assert.AreEqual(1m, 1.01m. TruncateEx(0)); Assert.AreEqual(-1m, -1.99m. TruncateEx(0)); Assert.AreEqual(-1m, -1.01m. TruncateEx(0)); }
这会为你工作吗?
Console.Write(((int)(3.4679999999*100))/100.0);
会((long)(3.4679 * 100)) / 100.0
给你想要的?
这是一个扩展方法:
public static decimal? TruncateDecimalPlaces(this decimal? value, int places) { if (value == null) { return null; } return Math.Floor((decimal)value * (decimal)Math.Pow(10, places)) / (decimal)Math.Pow(10, places); } // end
通用和快速的方法(没有Math.Pow()
/乘法)为System.Decimal
:
decimal Truncate(decimal d, byte decimals) { decimal r = Math.Round(d, decimals); if (d > 0 && r > d) { return r - new decimal(1, 0, 0, false, decimals); } else if (d < 0 && r < d) { return r + new decimal(1, 0, 0, false, decimals); } return r; }
如果您不太担心性能,并且最终结果可能是string,则以下方法将对浮动精度问题具有弹性:
string Truncate(double value, int precision) { if (precision < 0) { throw new ArgumentOutOfRangeException("Precision cannot be less than zero"); } string result = value.ToString(); int dot = result.IndexOf('.'); if (dot < 0) { return result; } int newLength = dot + precision + 1; if (newLength == dot + 1) { newLength--; } if (newLength > result.Length) { newLength = result.Length; } return result.Substring(0, newLength); }
这是我的TRUNC函数的实现
private static object Tranc(List<Expression.Expression> p) { var target = (decimal)p[0].Evaluate(); // check if formula contains only one argument var digits = p.Count > 1 ? (decimal) p[1].Evaluate() : 0; return Math.Truncate((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits); }
那这个呢?
Function TruncateDecimal2(MyValue As Decimal) As Decimal Try Return Math.Truncate(100 * MyValue) / 100 Catch ex As Exception Return Math.Round(MyValue, 2) End Try End Function
除了上面的解决scheme之外,还有另外一个方法可以实现。
decimal val=23.5678m,finalValue; //take the decimal part int decimalPos = val.ToString().IndexOf('.'); string decimalPart = val.ToString().Substring(decimalPosition+1,val.ToString().Length); //will result.56 string wholePart=val.ToString().Substring(0,decimalPos-1); //concantinate and parse for decimal. string truncatedValue=wholePart+decimalPart;//"23.56" bool isDecimal=Decimal.tryParse(truncatedValue,out finalValue);//finalValue=23.56
在某些情况下,这可能就足够了。
我有一个小数值SubCent = 0.0099999999999999999999999999M往往格式为| SubCent:0.010000 | 通过string.Format("{0:N6}", SubCent );
和许多其他格式select。
我的要求是不是四舍五入SubCent值,但不logging每个数字。
以下符合我的要求:
string.Format("SubCent:{0}|", SubCent.ToString("N10", CultureInfo.InvariantCulture).Substring(0, 9));
返回string: | SubCent:0.0099999 |
为了适应具有整数部分的值,以下是开始。
tmpValFmt = 567890.0099999933999229999999M.ToString("0.0000000000000000000000000000"); decPt = tmpValFmt.LastIndexOf("."); if (decPt < 0) decPt = 0; valFmt4 = string.Format("{0}", tmpValFmt.Substring(0, decPt + 9));
其中返回string:
valFmt4 = "567890.00999999"
其实你想要3.4679的3.46。 这只是字符的表示,所以与math函数无关。math函数并不打算做这个工作。 只需使用下面的代码。
Dim str1 As String str1="" str1 ="3.4679" Dim substring As String = str1.Substring(0, 3) ' Write the results to the screen. Console.WriteLine("Substring: {0}", substring) Or Please use the following code. Public function result(ByVal x1 As Double) As String Dim i as Int32 i=0 Dim y as String y = "" For Each ch as Char In x1.ToString If i>3 then Exit For Else y + y +ch End if i=i+1 Next return y End Function
上面的代码可以修改为任何数字将下面的代码放在button单击事件中
Dim str As String str= result(3.4679) MsgBox("The number is " & str)