locked
defects in type decimal and double RRS feed

  • 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

Answers

  • 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
    			l = Add(l, Divide(z, divisor))
    			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")
    
    		Console.ReadLine()
    
    	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 jo0ls 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
    			l = Add(l, Divide(z, divisor))
    			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")
    
    		Console.ReadLine()
    
    	End Sub
    
    End Module
    
    

    (Remove the lines with iterationCount if desired.)

    --
    Andrew

    Monday, January 9, 2012 10:19 PM