以下是示例代码
Dim sPrice : sPrice = "34,55555"
MsgBox(cCur(sPrice))
MsgBox(cDbl(sPrice))
If cCur(sPrice) = cDbl(sPrice) Then
MsgBox("+")
End If
当你以sPrice作为另一个不以.55555结尾的数字时,所有数字都按预期工作。如何处理这种情况?
答案 0 :(得分:1)
这不是一个错误,它是一个功能?
简短回答:所描述的差异有没有好的解决方案,因为Round()
函数没有声明"round to even" rule。
Comparison Operators (VBScript)引用太粗糙和简短:如果两个表达式都是数字,则执行数字比较。在不同数字子类型的情况下,没有关于隐式转换的内容,也没有关于舍入的内容。
类似地,Conversion Functions reference在CInt()
的情况下说了一些关于(隐式)四舍五入的事情,但在CCur()
的情况下却没有。
因此,让我们尝试明确地执行所有必要的转换和舍入。
第一次尝试。虽然cCur(Round( cDbl(sPrice),4)) = Round( cDbl(sPrice),4)
比较似乎非常接近,但Round()
仍然提供错误的34,5555
而不是34,5556
。此外,繁琐和繁琐的代码(见下文最后)仅涵盖特殊情况。因此,让我们尽可能地写出一般真正的脚本。
证明Round()
函数未声明“围绕甚至”规则:
'''''''''''''''''''''''''''''''''''''''''''''''
' VB Script Document: rounding Double / Currency
'
' Synopsis
' Checks whether "round to even" rule always holds.
'
' Description
' Shows some "slope discontinuity" points where "round to even" rule fails
' and where returns to right behaviour.
'
' Parameters
' Optional positional (variant subtype)
'
' #1 (long): fractional part to test (as integer without decimal point)
' if not numeric or not present then variable strFract defaults to 55555
'
' #2 (any): way of conversion values to Currency subtype, variable booFromStr
' if not present (label FAL) then from Double as CCur( CDbl( sPrice))
' else (label TRU, results are less pompous) from String as CCur( sPrice)
'
' Usage examples (all with pretty spectacular results)
'
' cscript 40793437.vbs
' cscript 40793437.vbs 12335
' cscript 40793437.vbs 12345
'
'''''''''''''''''''''''''''''''''''''''''''''''
option explicit
On Error GoTo 0
Dim sPrice, nn, ii, strVal, dblVal, curVal, curLav, strCur, booFromStr _
, strTailNowN, strTailLast, strTailCurN, strTailCurL, sDecPoint _
, strValChange, strCurChange, strResult, strResCur, arrParams, strFract _
, strFractNn, sAux, strFromStr ', numChangesVal, numChangesCur
Set arrParams = WScript.Arguments
booFromStr = ( arrParams.Count > 1 )
strFromStr = UCase( Left( Cstr( booFromStr), 3))
strFract = "55555"
If arrParams.Count > 0 Then
sAux = CStr( arrParams(0))
If IsNumeric( sAux) Then strFract = Right( strFract & CStr( Abs( CLng(sAux))), 5)
End If
sDecPoint = Mid( FormatNumber( 0.1, 1, true, false, -2), 2, 1)
strResult = "" : strResCur = ""
For nn = 3 To 5
strFractNn = sDecPoint & Right( strFract, nn)
sAux = vbTab & "Round(0." & Mid( strFractNn, 2) & "," & CStr( nn-1) & ")="
strResult = strResult & vbNewLine & strFromStr _
& " Double round change / Currency round status" & sAux _
& CStr( Round( CDbl( "0" & strFractNn), nn-1))
strResCur = strResCur & vbNewLine & strFromStr _
& " Currency round change / Double round status" & sAux
If Not booFromStr Then
strResCur = strResCur & CStr( Round( CCur( CDbl( "0" & strFractNn)), nn-1))
Else
strResCur = strResCur & CStr( Round( CCur( ( "0" & strFractNn)), nn-1))
End If
strTailLast = "" : strTailCurL = ""
'numChangesVal = 0
'numChangesCur = 0
For ii = -140000 to 140000
If ii < 0 Then
sPrice = "-" & CStr( Abs( ii + 1) ) & strFractNn
Else
sPrice = CStr( ii) & strFractNn
End If
dblVal = CDbl( sPrice)
strVal = Right( Space(18) _
& FormatNumber( Round( dblVal, nn-1), nn-1, true, false, -2), 18)
strTailNowN = Right(strVal,1)
If strTailLast = strTailNowN Then sAux = " == " Else sAux = " -> "
strValChange= strTailLast & sAux & strTailNowN
If Not booFromStr Then
curVal = Round( CCur( dblVal), nn-1)
curLav = curVal
If nn = 5 Then curLav = CCur( dblVal)
If Not (curLav = curVal) Then MsgBox curLav & vbCrLf & curVal
Else
curVal = Round( CCur( sPrice), nn-1)
curLav = curVal
If nn = 5 Then curLav = CCur( sPrice)
If Not (curLav = curVal) Then MsgBox curLav & vbCrLf & curVal
End If
strCur = Right( Space(18) & FormatNumber( curVal, nn-1, true, false, -2), 18)
strTailCurN = Right( strCur, 1)
If strTailCurL = strTailCurN Then sAux = " == " Else sAux = " -> "
strCurChange= strTailCurL & sAux & strTailCurN
If Not( strTailCurL = strTailCurN) Then
'numChangesCur = numChangesCur + 1
If Not (strTailCurL = "") Then
strResCur = strResCur & vbNewLine _
& strCur & " " & strCurChange & " /" & strVal & " " & strValChange
End If
strTailCurL = strTailCurN
End If
If Not( strTailLast = strTailNowN) Then
'numChangesVal = numChangesVal + 1
If Not (strTailLast = "") Then
strResult = strResult & vbNewLine _
& strVal & " " & strValChange & " /" & strCur & " " & strCurChange
End If
strTailLast = strTailNowN
End If
'If ( numChangesVal > 20 ) or ( numChangesCur > 20 ) Then Exit For
Next
Next
strResult = strResult & vbNewLine & strResCur
Wscript.Echo strResult
Wscript.Quit
输出有标签以便于解释,并显示OP的假设“当您将sPrice作为另一个不以.55555 结尾的数字全部按预期工作时< / strike>“错了:
==> cscript D:\VB_scripts\SO\40793437.vbs 12345
FAL Double round change / Currency round status Round(0.345,2)=0,34
-327,35 4 -> 5 / -327,34 4 == 4
-255,34 5 -> 4 / -255,34 4 == 4
-9,35 4 -> 5 / -9,34 4 == 4
-7,34 5 -> 4 / -7,34 4 == 4
-2,35 4 -> 5 / -2,34 4 == 4
-1,34 5 -> 4 / -1,34 4 == 4
2,35 4 -> 5 / 2,34 4 == 4
3,34 5 -> 4 / 3,34 4 == 4
8,35 4 -> 5 / 8,34 4 == 4
10,34 5 -> 4 / 10,34 4 == 4
256,35 4 -> 5 / 256,34 4 == 4
328,34 5 -> 4 / 328,34 4 == 4
FAL Double round change / Currency round status Round(0.2345,3)=0,234
-67 108,235 4 -> 5 / -67 108,234 4 == 4
-65 535,234 5 -> 4 / -65 535,234 4 == 4
-8 388,235 4 -> 5 / -8 388,234 4 == 4
-8 191,234 5 -> 4 / -8 191,234 4 == 4
-261,235 4 -> 5 / -261,234 4 == 4
-255,234 5 -> 4 / -255,234 4 == 4
256,235 4 -> 5 / 256,234 4 == 4
262,234 5 -> 4 / 262,234 4 == 4
8 192,235 4 -> 5 / 8 192,234 4 == 4
8 389,234 5 -> 4 / 8 389,234 4 == 4
65 536,235 4 -> 5 / 65 536,234 4 == 4
67 109,234 5 -> 4 / 67 109,234 4 == 4
FAL Double round change / Currency round status Round(0.12345,4)=0,1234
-131 071,1234 5 -> 4 / -131 071,1234 5 -> 4
-838,1235 4 -> 5 / -838,1235 5 == 5
-511,1234 5 -> 4 / -511,1234 5 -> 4
512,1235 4 -> 5 / 512,1235 4 -> 5
839,1234 5 -> 4 / 839,1235 5 == 5
131 072,1235 4 -> 5 / 131 072,1235 4 -> 5
FAL Currency round change / Double round status Round(0.345,2)=0,34
FAL Currency round change / Double round status Round(0.2345,3)=0,234
FAL Currency round change / Double round status Round(0.12345,4)=0,1235
-131 071,1234 5 -> 4 / -131 071,1234 5 -> 4
-8 191,1235 4 -> 5 / -8 191,1234 4 == 4
-511,1234 5 -> 4 / -511,1234 5 -> 4
-127,1235 4 -> 5 / -127,1234 4 == 4
-63,1234 5 -> 4 / -63,1234 4 == 4
-15,1235 4 -> 5 / -15,1234 4 == 4
16,1234 5 -> 4 / 16,1234 4 == 4
64,1235 4 -> 5 / 64,1234 4 == 4
128,1234 5 -> 4 / 128,1234 4 == 4
512,1235 4 -> 5 / 512,1235 4 -> 5
8 192,1234 5 -> 4 / 8 192,1234 4 == 4
131 072,1235 4 -> 5 / 131 072,1235 4 -> 5
输出第二部分显示了另一个小部分的斜率不连续点点:
==> cscript D:\VB_scripts\SO\40793437.vbs 12335
FAL Double round change / Currency round status Round(0.335,2)=0,34
-10 485,33 4 -> 3 / -10 485,34 4 == 4
-8 191,34 3 -> 4 / -8 191,34 4 == 4
-327,33 4 -> 3 / -327,34 4 == 4
-255,34 3 -> 4 / -255,34 4 == 4
-81,33 4 -> 3 / -81,34 4 == 4
-63,34 3 -> 4 / -63,34 4 == 4
64,33 4 -> 3 / 64,34 4 == 4
82,34 3 -> 4 / 82,34 4 == 4
256,33 4 -> 3 / 256,34 4 == 4
328,34 3 -> 4 / 328,34 4 == 4
8 192,33 4 -> 3 / 8 192,34 4 == 4
10 486,34 3 -> 4 / 10 486,34 4 == 4
FAL Double round change / Currency round status Round(0.2335,3)=0,234
-16 776,233 4 -> 3 / -16 776,234 4 == 4
-16 383,234 3 -> 4 / -16 383,234 4 == 4
-2 096,233 4 -> 3 / -2 096,234 4 == 4
-2 047,234 3 -> 4 / -2 047,234 4 == 4
-130,233 4 -> 3 / -130,234 4 == 4
-127,234 3 -> 4 / -127,234 4 == 4
128,233 4 -> 3 / 128,234 4 == 4
131,234 3 -> 4 / 131,234 4 == 4
2 048,233 4 -> 3 / 2 048,234 4 == 4
2 097,234 3 -> 4 / 2 097,234 4 == 4
16 384,233 4 -> 3 / 16 384,234 4 == 4
16 777,234 3 -> 4 / 16 777,234 4 == 4
FAL Double round change / Currency round status Round(0.12335,4)=0,1234
-209,1233 4 -> 3 / -209,1233 3 == 3
-127,1234 3 -> 4 / -127,1234 3 -> 4
-26,1233 4 -> 3 / -26,1233 3 == 3
-15,1234 3 -> 4 / -15,1234 3 -> 4
16,1233 4 -> 3 / 16,1233 4 -> 3
27,1234 3 -> 4 / 27,1233 3 == 3
128,1233 4 -> 3 / 128,1233 4 -> 3
210,1234 3 -> 4 / 210,1233 3 == 3
FAL Currency round change / Double round status Round(0.335,2)=0,34
FAL Currency round change / Double round status Round(0.2335,3)=0,234
FAL Currency round change / Double round status Round(0.12335,4)=0,1234
-131 071,1233 4 -> 3 / -131 071,1234 4 == 4
-65 535,1234 3 -> 4 / -65 535,1234 4 == 4
-16 383,1233 4 -> 3 / -16 383,1234 4 == 4
-2 047,1234 3 -> 4 / -2 047,1234 4 == 4
-1 023,1233 4 -> 3 / -1 023,1234 4 == 4
-511,1234 3 -> 4 / -511,1234 4 == 4
-255,1233 4 -> 3 / -255,1234 4 == 4
-127,1234 3 -> 4 / -127,1234 3 -> 4
-31,1233 4 -> 3 / -31,1234 4 == 4
-15,1234 3 -> 4 / -15,1234 3 -> 4
-3,1233 4 -> 3 / -3,1234 4 == 4
-1,1234 3 -> 4 / -1,1234 4 == 4
2,1233 4 -> 3 / 2,1234 4 == 4
4,1234 3 -> 4 / 4,1234 4 == 4
16,1233 4 -> 3 / 16,1233 4 -> 3
32,1234 3 -> 4 / 32,1234 4 == 4
128,1233 4 -> 3 / 128,1233 4 -> 3
256,1234 3 -> 4 / 256,1234 4 == 4
512,1233 4 -> 3 / 512,1234 4 == 4
1 024,1234 3 -> 4 / 1 024,1234 4 == 4
2 048,1233 4 -> 3 / 2 048,1234 4 == 4
16 384,1234 3 -> 4 / 16 384,1234 4 == 4
65 536,1233 4 -> 3 / 65 536,1234 4 == 4
131 072,1234 3 -> 4 / 131 072,1234 4 == 4
==>
为了完整起见,这是我的第一个尝试脚本和结果:
option explicit
On Error GoTo 0
Dim sR: sR = Wscript.ScriptName
check ("34,12355")
check ("34,55555")
Wscript.Echo sR
Wscript.Quit
Sub check (sPrice)
Dim bMatch
bMatch = ( cCur(sPrice) = cDbl(sPrice) )
sR = sR & vbNewLine & Cstr( bMatch) & Space( 1+Abs( bMatch)) & " a cCur = cDbl " _
& cCur(sPrice) & " = " & cDbl(sPrice)
bMatch = ( cCur(sPrice) = Round( cDbl(sPrice), 4) )
sR = sR & vbNewLine & Cstr( bMatch) & Space( 1+Abs( bMatch)) & " b cCur = cDbl " _
& cCur(sPrice) & " = " & Round( cDbl(sPrice), 4)
bMatch = ( Round( cCur(sPrice), 4) = cDbl(sPrice) )
sR = sR & vbNewLine & Cstr( bMatch) & Space( 1+Abs( bMatch)) & " c cCur = cDbl " _
& Round( cCur(sPrice), 4) & " = " & cDbl(sPrice)
bMatch = ( Round( cCur(sPrice), 4) = Round( cDbl(sPrice),4) )
sR = sR & vbNewLine & Cstr( bMatch) & Space( 1+Abs( bMatch)) & " d cCur = cDbl " _
& Round( cCur(sPrice), 4) & " = " & Round( cDbl(sPrice), 4)
bMatch = ( cCur(Round( cDbl(sPrice),4)) = Round( cDbl(sPrice),4) )
sR = sR & vbNewLine & Cstr( bMatch) & Space( 1+Abs( bMatch)) & " ? cCur = cDbl " _
& cCur(Round( cDbl(sPrice),4)) & " = " & Round( cDbl(sPrice), 4)
End Sub
输出:
==> cscript D:\VB_scripts\SO\40793437a.vbs
40793437a.vbs
True a cCur = cDbl 34,1236 = 34,12355
True b cCur = cDbl 34,1236 = 34,1236
True c cCur = cDbl 34,1236 = 34,12355
True d cCur = cDbl 34,1236 = 34,1236
True ? cCur = cDbl 34,1236 = 34,1236
False a cCur = cDbl 34,5556 = 34,55555
False b cCur = cDbl 34,5556 = 34,5555
False c cCur = cDbl 34,5556 = 34,55555
False d cCur = cDbl 34,5556 = 34,5555
True ? cCur = cDbl 34,5555 = 34,5555