if表示当x以.55555结尾时,数字cCur(x)和cDbl(x)不相等

时间:2016-11-24 19:29:19

标签: vbscript

以下是示例代码

Dim sPrice : sPrice = "34,55555"

MsgBox(cCur(sPrice))
MsgBox(cDbl(sPrice))

If cCur(sPrice) = cDbl(sPrice) Then
  MsgBox("+")
End If

当你以sPrice作为另一个不以.55555结尾的数字时,所有数字都按预期工作。如何处理这种情况?

1 个答案:

答案 0 :(得分:1)

这不是一个错误,它是一个功能

简短回答:所描述的差异有没有好的解决方案,因为Round()函数没有声明"round to even" rule

Comparison Operators (VBScript)引用太粗糙和简短:如果两个表达式都是数字,则执行数字比较。在不同数字子类型的情况下,没有关于隐式转换的内容,也没有关于舍入的内容。 类似地,Conversion Functions referenceCInt()的情况下说了一些关于(隐式)四舍五入的事情,但在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