截断问题-双精度数据与十进制数据类型 [英] Truncate Issue - Double vs Decimal Data Type

查看:116
本文介绍了截断问题-双精度数据与十进制数据类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将程序截断到百分之一.我首先看了Math.Truncate,但它被截断为整数.为了能够截断到我想要的任何小数位,我决定编写自己的函数.这是:

 私有 功能 TruncateFld( ByVal  dblValue  As   Double 可选  ByVal  intDecimalPlaces  As  整数 =  0 ) As   Double 
     Dim  sb  As   New  System.Text. StringBuilder(" )
    对于诠释 As  整数 =  1   intDecimalPlaces
        sb.Append(" )
    下一步
    返回  CDbl (Math.Truncate(dblValue *  CInt (sb.ToString))/ CInt (sb.ToString))
结束 功能 




它似乎可行,但是当我将其放在程序中时,我发现了一个问题.当我传入16.9作为值,并传入2作为要舍入的小数位数时,返回16.89.在返回行上,dblValue * CInt(sb.ToString)为16.9 * 100,而不是计算为1690,而是返回1689.9999999999998.

这是怎么回事,我该如何解决?

---------------------------
关于答案1:

我将返回行更改为:
返回CDbl(Math.Truncate(String.Format("0:0.0",dblValue)* CInt(sb.ToString))/CInt(sb.ToString))
并收到此错误:
从字符串"0:0.0"到类型"Double"的转换无效.

好的...您的意思是只用它来进行截断.问题在于它似乎并没有截断,而是圆了.所以也许我的格式错误...我尝试过:
Return dblValue.ToString("0.00"),但是如果我传入的数字是16.9091,则当我真正想要16.90时返回16.91.

---------------------------
关于答案4:
我不知道Math.Pow函数.这对于摆脱我的stringbuilder的工作真的很棒.但是,您的代码仍然无法解决问题.在测试中,我使用数字1.21将其四舍五入到小数点后两位.在您的代码中,Value - intPortion变为1.21-1,出于某种疯狂的原因,它变为.2099999999996而不是.21.您能否让我知道您在哪里找到有关该问题的信息?因为我被教导只在处理货币时使用小数类型,而在其他任何地方都使用双精度类型.所以现在我想我的程序中可能存在疯狂的计算错误.

--------------
关于评论:
你是对的.我在第三个答案中使用了代码,只是将一些变量名更改为我自己的命名约定.单行语句确实有效.感谢您的帮助,William Winner!猜猜我必须停止使用Double数据类型.


对于其他有类似问题的人,我发现了本文 [ intPortion As = Math.Truncate(Value)



现在,获取带有所需位数的小数部分.

  Dim  decimalPortion  As   = Math.Truncate((Value-intPortion)* Math.Pow( 10 ,NumberOfDecimals))



现在返回整数部分加上小数部分,将小数部分转换回小数.

 返回 intPortion +(decimalPortion/Math.Pow( 10 ,NumberOfDecimals) )



如果您正在做数学运算,则根本不应该使用字符串...没有必要.

另外,如果您想要返回"16.90"(如果您想输入两位数),则需要返回一个字符串,而不是双精度字符.

无论如何,我的方式看起来像这样:

 私有 功能 Truncate( ByVal  As   Double 可选  ByVal  NumberOfDecimals  As  整数 =  0 ) As   Double 
     Dim  intPortion  As   = Math.Truncate (价值)
     Dim  decimalPortion  As   = Math.Truncate (((值-intPortion)* Math.Pow( 10 ,NumberOfDecimals))

    返回 intPortion +(decimalPortion/Math.Pow( 10 ,NumberOfDecimals))
结束 功能 




就像FYI ...更好,更简洁的方法是一行代码:

 返回(Math.Truncate(Value * Math.Pow( 10 , NumberOfDecimals))_
                /Math.Pow( 10 ,NumberOfDecimals))



至少在数学上由于某些原因,当值16.9为NumberOfDecimals为2时,Value * Math.Pow(10, NumberOfDecimals)也会返回16.89.


我做了一些研究. Double似乎有问题.

您可以尝试以下操作:将Doubles更改为Decimals.此功能按应有的方式工作:

 私有 功能 Truncate( ByVal  十进制,_
                          可选  ByVal  NumberOfDecimals  as  整数 =  0 ) as  返回(Math.Truncate(值*  CDec (Math.Pow( 10 ,NumberOfDecimals))
结束 功能 




[较小更改]将ByValue更改为ByVal


我认为在math.truncate方法中计算回合时存在一些错误.

当我尝试遵循以下值时,它将为我返回正确的值.

Math.Truncate(32.9 * 100)
32.9返回3290
15.9返回1590

但是当我尝试
16.9它返回了我1689

因此,我认为Math.Truncate方法中的计算存在一些问题.

[来自WW]
实际上,问题出在代码的乘法部分.如果您单步执行代码并进入QuickWatch(Shift + F9),仅键入16.9 * 100,则无论出于何种原因,它都会返回16.899999998. 16.9 * 10作品和16.9 * 1000作品,但不是16.9 * 100.


I need to truncate a double to the hundredths place for a program. I first looked at Math.Truncate, but it truncates to a whole number. In order to be able to truncate to whatever decimal place I want, I decided to write my own function. Here it is:

Private Function TruncateFld(ByVal dblValue As Double, Optional ByVal intDecimalPlaces As Integer = 0) As Double
    Dim sb As New System.Text.StringBuilder("1")
    For intI As Integer = 1 To intDecimalPlaces
        sb.Append("0")
    Next
    Return CDbl(Math.Truncate(dblValue * CInt(sb.ToString)) / CInt(sb.ToString))
End Function




It seems to work, but then when I put it in my program I found a problem. When I passed in 16.9 as the value and 2 as the number of decimal places to round to it returned 16.89. On the Return line, dblValue * CInt(sb.ToString) is 16.9 * 100 and instead of calculating to 1690 it comes back with 1689.9999999999998.

What is going on here and how can I fix it?

---------------------------
Regarding Answer 1:

I changed the Return line to this:
Return CDbl(Math.Truncate(String.Format("0 : 0.0", dblValue) * CInt(sb.ToString)) / CInt(sb.ToString))
and got this error:
Conversion from string "0 : 0.0" to type ''Double'' is not valid.

Okay...You meant just use that to do the truncate. The problem is that it doesn''t seem to truncate, it seems to round. So maybe I have the wrong format thing...I tried this:
Return dblValue.ToString("0.00") but if the number I pass in is 16.9091 it return 16.91 when I really want 16.90.

---------------------------
Regarding Answer 4:
I didn''t know about the Math.Pow function. That is really great for getting rid of my stringbuilder work around. However, your code still doesn''t solve the issue. In my testing I used the number 1.21 rounding it to 2 decimal places. In your code Value - intPortion becomes 1.21 - 1 which for some crazy reason becomes .2099999999996 instead of .21. Could you please let me know where you found the info about the problem being the double? Because I was taught to only use the Decimal type when dealing with currency and to use the Double type everywhere else. So now I''m thinking that there are probably crazy calculation errors all over my programs.

--------------
Regarding Comment:
You''re right. I was using the code in your 3rd answer and had just changed a few of the variable names to my own naming convention. The one line statement does work. Thanks for your help, William Winner! Guess I have to stop using the Double data type.


For anyone else having similar problems, I found
this article[^] which seems to describe the Double vs Decimal data type issue clearly.

解决方案

Honestly, it seems that you''re approaching this in a very strange way...using strings and all.

Look at it step by step.

First, get the integer portion. Ok, that''s easy

Dim intPortion As Long = Math.Truncate(Value)



Now, get the decimal portion with the number of digits that you want.

Dim decimalPortion As Long = Math.Truncate((Value - intPortion) * Math.Pow(10, NumberOfDecimals))



Now return the integer portion plus the decimal portion converting the decimal portion back into a decimal.

Return intPortion + (decimalPortion / Math.Pow(10, NumberOfDecimals))



If you are doing math, you shouldn''t use strings at all...there''s no need to.

Also, if your intent is to return "16.90" if you want 2 digits, then you need to return a string, not a double.

Anyway, my way put together looks like:

Private Function Truncate(ByVal Value As Double, Optional ByVal NumberOfDecimals As Integer = 0) As Double
    Dim intPortion As Long = Math.Truncate(Value)
    Dim decimalPortion As Long = Math.Truncate((Value - intPortion) * Math.Pow(10, NumberOfDecimals))

    Return intPortion + (decimalPortion / Math.Pow(10, NumberOfDecimals))
End Function




Just as an FYI...the better, more concise way would be one line of code:

Return (Math.Truncate(Value * Math.Pow(10, NumberOfDecimals)) _
                / Math.Pow(10, NumberOfDecimals))



...at least mathematically. For some reason, the Value * Math.Pow(10, NumberOfDecimals) also returns 16.89 when 16.9 is the value and NumberOfDecimals is 2.


I did a little research. It seems to be a problem with the Double.

You can try this though: Change your Doubles to Decimals. This function works the way it should:

Private Function Truncate(ByVal Value as Decimal, _
                          Optional ByVal NumberOfDecimals as Integer = 0) as Decimal
     Return (Math.Truncate(Value * CDec(Math.Pow(10, NumberOfDecimals))) _
             / Math.Pow(10, NumberOfDecimals))
End Function




[Minor change] Changed ByValue to ByVal


I think there is some bug in calculating the round about in math.truncate method.

When I tried following values it will return me the correct value.

Math.Truncate(32.9 * 100)
32.9 return 3290
15.9 returns 1590

but when I try
16.9 it returns me 1689

So I think there is some problem in calculation within Math.Truncate method.

[From WW]
Actually, the problem is in the multiplication part of the code. If you step through the code and go into the QuickWatch (Shift + F9) and just type 16.9 * 100, it return 16.899999998 for whatever reason. 16.9 * 10 works and 16.9 * 1000 works, but not 16.9 * 100.


这篇关于截断问题-双精度数据与十进制数据类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆