It's not fractions that count in currency, but totals.
Sounds weird? No, it doesn't.
Here's an example:
Total amount is 100 euro.
Tax 30% = 33.33 euro.
Excluding tax = 66.67 euro.
If you deal with multiple valuta, you increase the number of decimals, but you never actually work with fractions... euh? What does that mean?
Well, use integers throughout your software, but add a dot before DISPLAYING them to Joe User, so 33.33 would be stored as 33333.
Bookkeepers and accountants and the tax agency like regular numbers, stuff has to add up, nothing should be lost due to rounding.
If you deal a lot with foreign valuta, you may have to do things like this: store the numbers internally in multiple digits, but stil as an it, for example 6 digits behind the comma:
1.003274
would be stored as
1003274
However, if you would build a ledger or something similar, you would round things to make sure it all 'matches', meaning you'll end up with something like:
1000000
which is equivalent to
1.00
Quads help here greatly. Without quads this would be hard. (I've done it in the past using two integers, one for the 'full' numbers, one for the 'decimals', but quads are an easier way.)
You then need something to display them, like this...
Code: Select all
Procedure.s x_strex(var.l,format.s) ; convert int to string using a format field, format characters space and -+#.#
Protected s.s, fl.l, sl.l, *f.CHAR, *s.CHAR, p.l, sb.l
;
; *** format integer to string
;
; in: var.l - int var
; f.s - format
; out: .s - string
;
; convert int var to string using a pattern
;
; pattern elements:
;
; '#' - number or leading zero
; ' ' - space, number or (when there's no '+' or '-' used in the format) sign
; '+' - positive or negative indicator
; '.' - decimal sign
;
; examples:
;
; x_strex( 1234, "###") = "***"
; x_strex( 1234, "##.##") = "12.34"
; x_strex(-1234, "##.##") = "*****"
; x_strex( 1, ".#####") = ".00001"
; x_strex( -1, "+ .##") = "- .01"
;
fl = Len(format)
s = Str(var)
sl = Len(s)
;
*f.CHAR = @format+fl*#Charsize ; using two pointers and two counters
*s.CHAR = @s+sl*#Charsize ; *f and *s are the pointers, fl and sl are the counters
;
If PeekC(@format) = '+' ; remember if there is a sign in a fixed place
p = 2
ElseIf PeekC(@format) = '-'
p = 1
Else
p = 0
EndIf
;
While fl > 0
fl = fl-1
*f = *f-#Charsize ; we could be in unicode mode...
If *f\c = '.' ; skip a dot if we pass one
Else
sl = sl-1
If sl >= 0
*s = *s-#Charsize
sb = *s\c ; sb contains the digit, AND is used as a flag
EndIf
Select *f\c
Case '-' ; ah, a sign in a fixed place
If sb = '-'
sb = -1 ; if sb = -1 we've managed to store the sign
Else
*f\c = ' '
EndIf
Case '+' ; same thing for the +
If sb = '-'
*f\c = sb
sb = -1
EndIf
Case '#' ; if we have data that is not a sign we're gonna fill it in
If sb = '-' Or sl < 0
*f\c = '0' ; otherwise it's going to be a zero
Else
*f\c = *s\c
EndIf
Case ' ' ; if there is no fixed spot for a sign we'll store the minus
If sb = '-' ; immediately on the first space we encounter
If p = 0
*f\c = '-'
sb = -1
EndIf
ElseIf sb <> -1 And sl >= 0 ; otherwise we'll just gonna fil it in
*f\c = *s\c
EndIf
EndSelect
EndIf
Wend
;
If sb = '-' Or sl > 0 ; if the sign wasn't stored or there was some data left
format = LSet("",Len(format),"*") ; we'll put in some stars to indicate overflow
EndIf
;
ProcedureReturn format
EndProcedure