For some money calculations I used the following procedures...
Code: Select all
; REFERENCES:
; -----------
; Currency Arithmetic Functions :
; http://msdn.microsoft.com/en-us/library/windows/desktop/ms221356%28v=vs.85%29.aspx
; -
; Data Type Conversion Functions:
; http://msdn.microsoft.com/en-us/library/windows/desktop/ms221582%28v=vs.85%29.aspx
; -
; Locale IDs (lcid):
; http://msdn.microsoft.com/en-us/goglobal/bb964664
;Win x86 -ASCII & Unicode
#VARCMP_LT = 0
#VARCMP_EQ = 1
#VARCMP_GT = 2
#VARCMP_NULL = 3
Structure decimal
wReserved.w
scale.b
sign.b
hi32.l
lo64.q
EndStructure
Import "oleaut32.lib"
VarCyFromStr.l (strIn.p-bstr, lcid.l, dwFlags.l, *pcyOut.q ) As "_VarCyFromStr@16"
VarBstrFromCy.l (cyIn.q, lcid.l, dwFlags.l, *pbstrOut.p-bstr) As "_VarBstrFromCy@20"
VarCyFromDec.l (*pdecIn.decimal, *pcyOut.q ) As "_VarCyFromDec@8"
VarDecFromStr.l (strIn.p-bstr, lcid.l, dwFlags.l, *pdecOut.decimal) As "_VarDecFromStr@16"
VarDecDiv.l (*pdecLeft.decimal, *pdecRight.decimal, *pdecResult.decimal) As "_VarDecDiv@12"
VarCyRound.l (cyIn.q, cDecimals.l, *pcyResult.q) As "_VarCyRound@16"
VarCyAdd.l (cyLeft.q, cyRight.q, *pcyResult.q) As "_VarCyAdd@20"
VarCyMul.l (cyLeft.q, cyRight.q, *pcyResult.q) As "_VarCyMul@20"
VarCyMulI4.l (cyLeft.q, lRight.l, *pcyResult.q) As "_VarCyMulI4@16"
VarCyMulI8.l (cyLeft.q, lRight.q, *pcyResult.q) As "_VarCyMulI8@20"
VarCySub.l (cyLeft.q, cyRight.q, *pcyResult.q) As "_VarCySub@20"
VarCyAbs.l (cyIn.q, *pcyResult.q) As "_VarCyAbs@12"
VarCyFix.l (cyIn.q, *pcyResult.q) As "_VarCyFix@12"
VarCyInt.l (cyIn.q, *pcyResult.q) As "_VarCyInt@12"
VarCyNeg.l (cyIn.q, *pcyResult.q) As "_VarCyNeg@12"
VarCyCmp.l (cyLeft.q, cyRight.q ) As "_VarCyCmp@16"
VarCyCmpR8.l (cyLeft.q, dblRight.d ) As "_VarCyCmpR8@16"
EndImport
Procedure.s ReadBstr(*String.s)
Result$ = ""
If *String
length.l = WideCharToMultiByte_(#CP_ACP, 0, *String, -1, 0, 0, 0, 0)
*Buffer.l = AllocateMemory(length)
If *Buffer
WideCharToMultiByte_(#CP_ACP, 0, *String, -1, *Buffer, length, 0, 0)
Result$ = PeekS(*Buffer, length, #PB_Ascii)
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Procedure.s FillZeros(StringIn.s, Decimals.l)
pos.i = 0
retval.s = ""
length.i = Len(StringIn)
pos = FindString(StringIn, ".", 1)
If pos
If pos > length-decimals
retval = LSet(StringIn, pos+Decimals, "0")
ProcedureReturn retval
Else
retval = StringIn
ProcedureReturn retval
EndIf
Else
retval = LSet(StringIn + ".", length + 1 + Decimals, "0")
ProcedureReturn retval
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s RoundCy(StringIn.s, Decimals.l)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
retval.s = ""
If Decimals > 4
Decimals = 4
EndIf
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn <>""
If VarCyFromStr(StringIn, lcid, 0, @cy) = #S_OK
If VarCyRound(cy, Decimals, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = FillZeros(ReadBstr(PeekL(bstr)), Decimals)
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s AddCy(StringIn1.s, StringIn2.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
cy1.q = 0
cy2.q = 0
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>"" And StringIn2 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK And VarCyFromStr(StringIn2, lcid, 0, @cy2) = #S_OK
If VarCyAdd(cy1, cy2, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s SubCy(StringIn1.s, StringIn2.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
cy1.q = 0
cy2.q = 0
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>"" And StringIn2 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK And VarCyFromStr(StringIn2, lcid, 0, @cy2) = #S_OK
If VarCySub(cy1, cy2, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s MulCy(StringIn1.s, StringIn2.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
cy1.q = 0
cy2.q = 0
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>"" And StringIn2 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK And VarCyFromStr(StringIn2, lcid, 0, @cy2) = #S_OK
If VarCyMul(cy1, cy2, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s MulCyLong(StringIn1.s, Int32.l)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
cy1.q = 0
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK
If VarCyMulI4(cy1, Int32, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s MulCyQuad(StringIn1.s, Int64.q)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
cy1.q = 0
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK
If VarCyMulI8(cy1, Int64, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s DivCy(StringIn1.s, StringIn2.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
dec.decimal
dec1.decimal
dec2.decimal
retval.s = ""
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn1 <>"" And StringIn2 <>""
If VarDecFromStr(StringIn1, lcid, 0, @dec1) = #S_OK And VarDecFromStr(StringIn2, lcid, 0, @dec2) = #S_OK
If VarDecDiv(@dec1, @dec2, @dec) = #S_OK
If VarCyFromDec(@dec, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s NegCy(StringIn.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
retval.s = ""
If Decimals > 4
Decimals = 4
EndIf
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn <>""
If VarCyFromStr(StringIn, lcid, 0, @cy) = #S_OK
If VarCyNeg(cy, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s AbsCy(StringIn.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
retval.s = ""
If Decimals > 4
Decimals = 4
EndIf
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn <>""
If VarCyFromStr(StringIn, lcid, 0, @cy) = #S_OK
If VarCyAbs(cy, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s IntCy(StringIn.s)
lcid.l = 1033
dwFlags.l = 0
cy.q = 0
retval.s = ""
If Decimals > 4
Decimals = 4
EndIf
bstr.l=SysAllocStringLen_(bstr,255)
If bstr And StringIn <>""
If VarCyFromStr(StringIn, lcid, 0, @cy) = #S_OK
If VarCyInt(cy, @cy) = #S_OK
If VarBstrFromCy(cy, lcid, 0, bstr) = #S_OK
retval = ReadBstr(PeekL(bstr))
SysFreeString_(bstr)
ProcedureReturn retval
EndIf
EndIf
EndIf
SysFreeString_(bstr)
EndIf
ProcedureReturn retval
EndProcedure
Procedure.s FixCy(StringIn.s)
ProcedureReturn IntCy(StringIn)
EndProcedure
Procedure.l CmpCy(StringIn1.s, StringIn2.s)
lcid.l = 1033
dwFlags.l = 0
cy1.q = 0
cy2.q = 0
retval.l = -1
If StringIn1 <>"" And StringIn2 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK And VarCyFromStr(StringIn2, lcid, 0, @cy2) = #S_OK
retval = VarCyCmp(cy1, cy2)
EndIf
EndIf
ProcedureReturn retval
EndProcedure
Procedure.l CmpCyDouble(StringIn1.s, Double.d)
lcid.l = 1033
dwFlags.l = 0
cy1.q = 0
retval.l = -1
If StringIn1 <>""
If VarCyFromStr(StringIn1, lcid, 0, @cy1) = #S_OK
retval = VarCyCmpR8(cy1, Double)
EndIf
EndIf
ProcedureReturn retval
EndProcedure
Debug RoundCy("6462.6789865",2)
Debug AddCy("323.7674", "8872.5")
Debug MulCy("8211.45", "0.567")
Debug NegCy("-121.23")
Debug AbsCy("-121.789")
strg$ = RoundCy(MulCy(AddCy(AddCy("12.32","9988"),"1.2"),"0.78"),4)
Debug strg$
Debug RoundCy(MulCyQuad("67531.632", 23233), 2)
Debug DivCy("345.123","1.2")
Debug FixCy("345.123")
dbl.d = 44.9999
Debug CmpCyDouble("45",dbl)