0

I tried the equivalent of Michael Meadows EDIT 2, but in VB.NET and got a different result. (Specifically both the Double and Decimal results were 600000.0238418580.)

I have determined the difference is with the compile-time accuracy of a Single division stored into a Single and when you force the division to occur at runtime.

So, THREE_FIFTHS and vTHREE_FIFTHS provide different results for the asDecimal summation:

const ONE_MILLION As Integer = 1000000

Dim THREEsng As Single = 3!
Dim FIVEsng As Single = 5!
Dim vTHREE_FIFTHS As Single = THREEsng / FIVEsng

const THREE_FIFTHS As Single = 3! / 5!

Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"))
Dim asSingle As Single = 0!
Dim asDouble As Double = 0#
Dim asDecimal As Decimal = 0@

For i As Integer = 1 To ONE_MILLION
    asSingle += CSng(THREE_FIFTHS)
    asDouble += CDbl(THREE_FIFTHS)
    asDecimal += CDec(THREE_FIFTHS)
Next
Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION)
Console.WriteLine("Single: {0}", asSingle.ToString("F10"))
Console.WriteLine("Double: {0}", asDouble.ToString("F10"))
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"))

Console.WriteLine("vThree Fifths: {0}", vTHREE_FIFTHS.ToString("F10"))
asSingle = 0!
asDouble = 0#
asDecimal = 0@

For i As Integer = 1 To ONE_MILLION
    asSingle += CSng(vTHREE_FIFTHS)
    asDouble += CDbl(vTHREE_FIFTHS)
    asDecimal += CDec(vTHREE_FIFTHS)
Next
Console.WriteLine("Six Hundred Thousand: {0:F10}", vTHREE_FIFTHS * ONE_MILLION)
Console.WriteLine("Single: {0}", asSingle.ToString("F10"))
Console.WriteLine("Double: {0}", asDouble.ToString("F10"))
Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"))

The result with the difference hightlighted is:

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 600000.0238418580
Decimal: 600000.0238418580
vThree Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 600000.0238418580
Decimal: 600000.0000000000

My question is, can you get VB.NET to get a Const Single expression with the equivalent of the runtime result? (I.e. produce a THREE_FIFTHS with the same results as vTHREE_FIFTHS.)

Community
  • 1
  • 1
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101

1 Answers1

0

It does look like the answer is "it can't be done" as, as pointed out in an answer to my similar question for C#, the compile-time constant is not really constant but reinterpreted in each context of use (and differently to C#). Specifically the CDec compile-time cast produces a different result to the runtime equivalent.

Sub Main
        const ONE_MILLION As Integer = 1000000

        Dim THREEsng As Single = 3!
        Dim FIVEsng As Single = 5!
        Dim vTHREE_FIFTHS As Single = THREEsng / FIVEsng

        const THREE_FIFTHS As Single = 3! / 5!

        Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"))
        Console.WriteLine(GetByteString(THREE_FIFTHS))
        Dim asSingle As Single = 0!
        Dim asDouble As Double = 0#
        Dim asDecimal As Decimal = 0@

        For i As Integer = 1 To ONE_MILLION
            asSingle += CSng(THREE_FIFTHS)
            asDouble += CDbl(THREE_FIFTHS)
            asDecimal += CDec(THREE_FIFTHS)
        Next
        Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION)
        Console.WriteLine("Single: {0}", asSingle.ToString("F10"))
        Console.WriteLine("Double: {0}", asDouble.ToString("F10"))
        Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"))
        Console.WriteLine(GetByteString(CSng(THREE_FIFTHS)))
        Console.WriteLine(GetByteString(CDbl(THREE_FIFTHS)))
        Console.WriteLine(GetByteString(CDec(THREE_FIFTHS)))

        Console.WriteLine("vThree Fifths: {0}", vTHREE_FIFTHS.ToString("F10"))
        Console.WriteLine(GetByteString(vTHREE_FIFTHS))
        asSingle = 0!
        asDouble = 0#
        asDecimal = 0@

        For i As Integer = 1 To ONE_MILLION
            asSingle += CSng(vTHREE_FIFTHS)
            asDouble += CDbl(vTHREE_FIFTHS)
            asDecimal += CDec(vTHREE_FIFTHS)
        Next
        Console.WriteLine("Six Hundred Thousand: {0:F10}", vTHREE_FIFTHS * ONE_MILLION)
        Console.WriteLine("Single: {0}", asSingle.ToString("F10"))
        Console.WriteLine("Double: {0}", asDouble.ToString("F10"))
        Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"))
        Console.WriteLine(GetByteString(CSng(vTHREE_FIFTHS)))
        Console.WriteLine(GetByteString(CDbl(vTHREE_FIFTHS)))
        Console.WriteLine(GetByteString(CDec(vTHREE_FIFTHS)))

End Sub

' Define other methods and classes here
Function GetByteString(d As Double) As String

    return "#" & string.Join("", BitConverter.GetBytes(d) _
             .Select(Function (b)b.ToString("X2")))

End Function

Function GetByteString(d As Decimal) As String

    return "D" & string.Join("", Decimal.GetBits(d) _
            .Select(Function (b)b.ToString("X8")))

End Function

Function GetByteString(f As Single) As String

    return "S" & string.Join("", BitConverter.GetBytes(f) _
            .Select(Function (b)b.ToString("X2")))

End Function

The output:

Three Fifths: 0.6000000000
S9A99193F
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 600000.0238418580
Decimal: 600000.0238418580
S9A99193F
#000000403333E33F
D64494C42000221B200000000000F0000
vThree Fifths: 0.6000000000
S9A99193F
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 600000.0238418580
Decimal: 600000.0000000000
S9A99193F
#000000403333E33F
D00000006000000000000000000010000

Community
  • 1
  • 1
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101