# defects in type decimal and double

• ### Question

• hello everyone. here is a very important matter to be corrected as soon as possible. generally,type double can display an answer correct to more than 20 decimal places. yes,it works fine until here except for exponential system. whenever i try to find a decimal raised to the power of a proper fraction, i get a correct answer but only upto 13 decimal places. that is not fair at all! it is important to get as high precision as possible. consider this example:-

input:2^(1/2)

output:1.4142135623731

this produces many errors when running a general purpose program requiring general calculations including "^".Just like this-

input:2^(1/2)*2^(1/2)

output:2.0000000000001

but if 2^(1/2) is computed upto 20 decimal places,answer i get is precise! 2.

most important thing-

i want that number of correct decimal places or approximation,which a windows 7 calculator has. i believe that this is someway easy to get rid of. please support.it is important for programs like calculator,worksheets,databases,etc. too!

Sunday, January 1, 2012 8:07 AM

• hmmmmmm.................................

please consider that till now,i was having no problem with any data type related issues and even now but neglecting situations of complex exponents.

jeff supreme

Write your own power function.  Extended precision types typically only have the basic operators add, subtract, multiply and divide.  Intel based systems typically have 13 bit precision for doubles which all higher precision types use for power functions.
Sunday, January 1, 2012 3:29 PM
• You may be forcing the calulation to use intermediate values that cannot retain the full precision of the original.  For instance,
MsgBox(2 ^ (1 / 2) * 2 ^ (1 / 2).ToString)
does not demonstrate the problem you have described, whereas
MsgBox((2 ^ (1 / 2)) * (2 ^ (1 / 2)).ToString)
does.  You need to ensure that intermediate values are maintained to at least the same precision as is required for the result. You should also ensure that all variables are explicitly declared as Double.

Decimal values wll be converted to Double for exponentation, although I can't see how that would produce the error you describe. What is the actal code you used to demonstrate the problem with Decimals?

Sunday, January 1, 2012 9:07 AM
• If you want to retain the most number of significant digits, use Decimal instead of Double.
http://msdn.microsoft.com/en-us/library/5c53yzyb(v=vs.80).aspx

The exponentiation operator uses Doubles only. If you want to use the full precision of the Decimal type with exponentiation, you will need to write your own exponentiation operator.
http://msdn.microsoft.com/en-us/library/zh100ckf(v=VS.80).aspx

The relationship between the Double or Decimal types and the String type is entirely controlled by the formatting information your provide when you do the conversion.  If you do not provide any formatting information and allow the system to default (for instance "msgbox(e1)" ) then the results will likely not be what you want.
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

Sunday, January 1, 2012 9:11 PM
• Since x^y = exp(y * ln(x))...

It may be possible to use other methods which converge more rapidly and/or are more accurate, but you can get quite close to the 2 you want:

```Imports System.Decimal

Module Module1

Const factorialDecSize As Integer = 27 ' Decimal only has sufficient size to hold (27!)
Const factorialDblSize As Integer = 37 ' to be determined empirically

Public factorialDec(factorialDecSize) As Decimal
Public factorialDbl(factorialDblSize) As Double

Private Sub SetUpFactorials()

' seed it with 0! = 1
factorialDec(0) = 1
For i = 1 To factorialDecSize
factorialDec(i) = factorialDec(i - 1) * i
Next

' seed the first Double factorial using the last Decimal value
factorialDbl(factorialDecSize) = factorialDec.Last

For i = factorialDecSize + 1 To factorialDblSize
factorialDbl(i) = factorialDbl(i - 1) * i
Next

End Sub

Function ln(x As Decimal) As Decimal
' from http://www.math.com/tables/expansion/log.htm
Dim l As Decimal = Divide(Subtract(x, 1D), Add(x, 1D))
Dim divisor As Integer = 3
Dim lSquared As Decimal = Multiply(l, l)
Dim z As Decimal = l
Dim prevValue As Decimal

Dim iterationCount As Integer = 0

Do
z = Multiply(z, lSquared)
prevValue = l
divisor += 2
iterationCount += 1
Loop Until l.Equals(prevValue) ' OrElse iterationCount > someSaneValue

Console.WriteLine("Iterations for ln({0}): {1}", x, iterationCount.ToString)

Return Multiply(l, 2D)

End Function

Function exp(x As Decimal) As Decimal

Dim r As Decimal = 1D
Dim x0 As Decimal = x
Dim prevValue As Decimal = Zero

Dim iterationCount As Integer = 0

Dim i As Integer = 0

Do
prevValue = r
If i < factorialDecSize Then
r = Add(r, Divide(x, factorialDec(i + 1)))
Else
' try to squeeze a few more digits from it
r = Add(r, CDec(x / factorialDbl(i + 1)))
End If

x = Multiply(x, x0)
i += 1
iterationCount += 1
Loop Until r.Equals(prevValue) OrElse i = factorialDblSize

Console.WriteLine("Iterations for exp({0}): {1}", x0, iterationCount.ToString)

Return r

End Function

Function pow(x As Decimal, y As Decimal) As Decimal
Return exp(Multiply(y, ln(x)))
End Function

Sub Main()
SetUpFactorials()

' calculate 2^0.5 using Decimals
Dim sqrt2 As Decimal = pow(2D, 0.5D)

' outputs 2.0000000000000000000000000000
Console.WriteLine(Multiply(sqrt2, sqrt2))

' the traditional way of writing 2
Console.WriteLine("2")

End Sub

End Module

```

(Remove the lines with iterationCount if desired.)

--
Andrew

Monday, January 9, 2012 10:19 PM

### All replies

• You may be forcing the calulation to use intermediate values that cannot retain the full precision of the original.  For instance,
MsgBox(2 ^ (1 / 2) * 2 ^ (1 / 2).ToString)
does not demonstrate the problem you have described, whereas
MsgBox((2 ^ (1 / 2)) * (2 ^ (1 / 2)).ToString)
does.  You need to ensure that intermediate values are maintained to at least the same precision as is required for the result. You should also ensure that all variables are explicitly declared as Double.

Decimal values wll be converted to Double for exponentation, although I can't see how that would produce the error you describe. What is the actal code you used to demonstrate the problem with Decimals?

Sunday, January 1, 2012 9:07 AM
• The mathematics of number systems are pretty much cast in stone. This will help Computer number format representation of numbers in binary. This will help Data Type Summary (Visual Basic) with the representation of the number data types in Visual Basic.
Sunday, January 1, 2012 11:53 AM
• well, simplified:

1. dim e1 as double=2^(1/2)
2. msgbox(e1)

output is 1.4142135623731 being displayed in the message box. but according to data type assigned, it should be 1.4142135623730950489 or more precise.

it will be best if i get this output:1.4142135623730950488016887242097(as in windows 7 calculator).isn't there any way to do any one of these. please tell me if there is any strong link in between string and double.

jeff supreme
Sunday, January 1, 2012 12:24 PM
• hmmmmmm.................................

please consider that till now,i was having no problem with any data type related issues and even now but neglecting situations of complex exponents.

jeff supreme
Sunday, January 1, 2012 12:31 PM
• hmmmmmm.................................

please consider that till now,i was having no problem with any data type related issues and even now but neglecting situations of complex exponents. i would like to have the code of win 7 calculator.i love it.

jeff supreme

jeff supreme
Sunday, January 1, 2012 12:32 PM
• hmmmmmm.................................

please consider that till now,i was having no problem with any data type related issues and even now but neglecting situations of complex exponents.

jeff supreme

Write your own power function.  Extended precision types typically only have the basic operators add, subtract, multiply and divide.  Intel based systems typically have 13 bit precision for doubles which all higher precision types use for power functions.
Sunday, January 1, 2012 3:29 PM
• If you want to retain the most number of significant digits, use Decimal instead of Double.
http://msdn.microsoft.com/en-us/library/5c53yzyb(v=vs.80).aspx

The exponentiation operator uses Doubles only. If you want to use the full precision of the Decimal type with exponentiation, you will need to write your own exponentiation operator.
http://msdn.microsoft.com/en-us/library/zh100ckf(v=VS.80).aspx

The relationship between the Double or Decimal types and the String type is entirely controlled by the formatting information your provide when you do the conversion.  If you do not provide any formatting information and allow the system to default (for instance "msgbox(e1)" ) then the results will likely not be what you want.
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

Sunday, January 1, 2012 9:11 PM
• oh my god! not  bad idea. but i can only make it out for a decimal n raised to the power an integer, and not decimal. please help me to write the code if there is a way to get there.
jeff supreme
Saturday, January 7, 2012 5:25 AM
• Calc.exe used to use IEEE 754 doubles for it's values, but microsoft completely re-wrote it to use an arbitrary precision library.

Note the paper than Mr.Chen links to - it's very well known indeed, often listed in the top 10 papers that every programmer should read (which tells you how common misunderstandings about floating point numbers are!)

If you want to mimic Calculator then you will need to use a library, there isn't one in the standard .Net framework (though there is BigDecimal in the J# redistributable).

• Edited by Saturday, January 7, 2012 12:09 PM
Saturday, January 7, 2012 12:09 PM
• oh my god! not  bad idea. but i can only make it out for a decimal n raised to the power an integer, and not decimal. please help me to write the code if there is a way to get there.

Since x^y = exp(y * ln(x)), you can calculate it using the logarithm and exponential functions, which you can calculate using the Maclaurin series shown at List of Maclaurin series of some common functions, which can be calculated entirely using the Decimal data type (Decimal.Divide etc.). You just need to keep calculating terms until they're small enough to not affect the last decimal place of the result.

--
Andrew

Saturday, January 7, 2012 2:57 PM
• You could start with a big number floating point library like this:
http://sine.codeplex.com/

Pow with a floating point exponent is not there yet, but it does have all the required components for building the function with big numbers, either as part of the existing library (if you want to work in C) or as VB code within your application.

Sunday, January 8, 2012 12:26 AM
• Since x^y = exp(y * ln(x))...

It may be possible to use other methods which converge more rapidly and/or are more accurate, but you can get quite close to the 2 you want:

```Imports System.Decimal

Module Module1

Const factorialDecSize As Integer = 27 ' Decimal only has sufficient size to hold (27!)
Const factorialDblSize As Integer = 37 ' to be determined empirically

Public factorialDec(factorialDecSize) As Decimal
Public factorialDbl(factorialDblSize) As Double

Private Sub SetUpFactorials()

' seed it with 0! = 1
factorialDec(0) = 1
For i = 1 To factorialDecSize
factorialDec(i) = factorialDec(i - 1) * i
Next

' seed the first Double factorial using the last Decimal value
factorialDbl(factorialDecSize) = factorialDec.Last

For i = factorialDecSize + 1 To factorialDblSize
factorialDbl(i) = factorialDbl(i - 1) * i
Next

End Sub

Function ln(x As Decimal) As Decimal
' from http://www.math.com/tables/expansion/log.htm
Dim l As Decimal = Divide(Subtract(x, 1D), Add(x, 1D))
Dim divisor As Integer = 3
Dim lSquared As Decimal = Multiply(l, l)
Dim z As Decimal = l
Dim prevValue As Decimal

Dim iterationCount As Integer = 0

Do
z = Multiply(z, lSquared)
prevValue = l
divisor += 2
iterationCount += 1
Loop Until l.Equals(prevValue) ' OrElse iterationCount > someSaneValue

Console.WriteLine("Iterations for ln({0}): {1}", x, iterationCount.ToString)

Return Multiply(l, 2D)

End Function

Function exp(x As Decimal) As Decimal

Dim r As Decimal = 1D
Dim x0 As Decimal = x
Dim prevValue As Decimal = Zero

Dim iterationCount As Integer = 0

Dim i As Integer = 0

Do
prevValue = r
If i < factorialDecSize Then
r = Add(r, Divide(x, factorialDec(i + 1)))
Else
' try to squeeze a few more digits from it
r = Add(r, CDec(x / factorialDbl(i + 1)))
End If

x = Multiply(x, x0)
i += 1
iterationCount += 1
Loop Until r.Equals(prevValue) OrElse i = factorialDblSize

Console.WriteLine("Iterations for exp({0}): {1}", x0, iterationCount.ToString)

Return r

End Function

Function pow(x As Decimal, y As Decimal) As Decimal
Return exp(Multiply(y, ln(x)))
End Function

Sub Main()
SetUpFactorials()

' calculate 2^0.5 using Decimals
Dim sqrt2 As Decimal = pow(2D, 0.5D)

' outputs 2.0000000000000000000000000000
Console.WriteLine(Multiply(sqrt2, sqrt2))

' the traditional way of writing 2
Console.WriteLine("2")