This project is read-only.
2
Vote

15/10 = 0.015 - Simple Division Failing

description

Declared 2 numbers as big decimal and division is not working correctly.
 
15/10 = 0.015
 
This basic division is not working then how can we rely the code for bigger calculations?

comments

cshung wrote Sep 29, 2012 at 8:01 AM

Just replace Div.vb with this one would work.

There are a couple issue with the division algorithm: Decimal point alignment algorithm has an off-by-one error, and there is no point to have TPS = Res.Length - aligned division should simply have 0 as decimal point.

Imports System.Numerics
Imports System.Runtime.CompilerServices
Imports BigDecimals.Math
Partial Class BigDecimal
'Private Shared Function ExmNivRem(ByVal x As BigDecimal, ByVal y As BigDecimal, ByRef remain As BigDecimal) As BigDecimal
'  Dim r As BigInteger = Nothing
'  Dim m As BigInteger = BigInteger.DivRem(x.Digits, y.Digits, r)
'  remain = New BigDecimal(r, 0)
'  Return New BigDecimal(m, CUInt(x.PointShift))
'End Function


Protected Friend Shared Function Division(ByVal X As BigDecimal, ByVal Y As BigDecimal) As BigDecimal
    ' Create a copy of x,y 
    Dim CX As BigDecimal = CType(X.Clone, BigDecimal)
    Dim CY As BigDecimal = CType(Y.Clone, BigDecimal)
    ' Check the Delta on the PointShift
    Dim ShiftPointDelta As New BigInteger(CInt(CX.DecimalPoint) - CInt(CY.DecimalPoint))
    If ShiftPointDelta > 0 Then
        CY.Digits = CY.Digits * (New BigInteger(10).Pow(ShiftPointDelta))
        CY.DecimalPoint = CUInt(CY.DecimalPoint + ShiftPointDelta)
    Else
        If ShiftPointDelta < 0 Then
            ShiftPointDelta = BigInteger.Abs(ShiftPointDelta)
            CX.Digits = CX.Digits * (New BigInteger(10).Pow(ShiftPointDelta))
            CX.DecimalPoint = CUInt(CX.DecimalPoint + ShiftPointDelta)
        End If
    End If
    ' Checks to see if the result would be negative.
    Dim MakeNegative As Boolean = False

    If CX.Digits.Sign = -1 Then
        MakeNegative = True
        CX.Digits = BigInteger.Abs(CX.Digits)
    End If
    If Not MakeNegative AndAlso CY.Digits.Sign = -1 Then
        MakeNegative = True
        CY.Digits = BigInteger.Abs(CY.Digits)
    End If
    Dim TPS As Integer = 0
    Dim rX As BigDecimal = Zero
    Dim [Mod] As BigInteger = Nothing
    Dim Res = BigInteger.DivRem(CX.Digits, CY.Digits, [Mod])
    rX.Digits = Res
    'TPS = Res.ToString.Length + 1
    'If Res = 0 Then TPS = 0
    Res = [Mod]
    While [Mod] <> 0
        Res = New BigInteger([Mod].ToByteArray) * New BigInteger(10)
        Res = BigInteger.DivRem(Res, CY.Digits, [Mod])
        TPS += 1
        rX.Digits = (rX.Digits * New BigInteger(10)) + Res
        If [Mod] = 0 Then Exit While
        If TPS > Internal_Limit Then Exit While
    End While
    rX.DecimalPoint = CUInt(TPS)
    If MakeNegative Then Return -rX
    Return rX
End Function
End Class

wrote Feb 12, 2013 at 11:04 PM