
ValC()
- Rook Zimbabwe
- Addict
- Posts: 4322
- Joined: Tue Jan 02, 2007 8:16 pm
- Location: Cypress TX
- Contact:
ValC()
I want to post a request for ValC() as well as a variable type of .c which would allow the adding and subtracting of CURRENCY VALUES without having to tack on a library or flip some annoying tricks!!! 

- Hroudtwolf
- Addict
- Posts: 803
- Joined: Sat Feb 12, 2005 3:35 am
- Location: Germany(Hessen)
- Contact:
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
- Rook Zimbabwe
- Addict
- Posts: 4322
- Joined: Tue Jan 02, 2007 8:16 pm
- Location: Cypress TX
- Contact:
IIRC doubles can be used for representing currency values. Not sure if it is as inaccurate as floats.Trond wrote:Because they are inaccurate. The currency type is usually implemented as a 64-bit integer that is scaled so the last two digits represents decimal places. That way there won't be float inaccuracies.Why not then simply use floats?
In storage, yes. In maths? I am sure you are right, but I need to have it explained.Trond wrote:Double is more accurate than floats, but integers are 100% accurate.
Integer 100 divided by 3 = 33
FP (single or double) 100 divided by 3 = 33.333' (with a few bits of imprecision in the 1/10000 or onwards mark).
Integer 100 divided by 3 in three operations, then the results added = 99
Float 100 divided by 3 in three operations, then the results added = 100.000 or pretty darn close.
So if the integer was currency there with 2dp and represented 1 dollar we would lose 1 cent.
As I said, I am sure you are right, but I can't see how. Can you educate me?
Dare2 cut down to size
33 stored in an integer is exactly 33, but 33.3333 stored in a floating point variable isn't exactly 33.3333 but something close. So not 100% accurate.Integer 100 divided by 3 = 33
FP (single or double) 100 divided by 3 = 33.333' (with a few bits of imprecision in the 1/10000 or onwards mark).
33.33 in a scaled integer would be EXACTLY 3.33, not 3.3299999237 (actual float precision on 3.33 with two decimals).
The real big problem in float math is loss of significance ( http://en.wikipedia.org/wiki/Loss_of_significance )
Do calculations with two very big but similar numbers and the precision
loss is very big:
Doubles do better but have the same problem:
Another big problem is that such errors increase the more calculations you perform on a value.
This is something you simply don't want in currency stuff.
Do calculations with two very big but similar numbers and the precision
loss is very big:
Code: Select all
a.f = 100000001.0
Debug a - 100000000.0
Code: Select all
b.d = 100000000000000001.0
Debug b - 100000000000000000.0
This is something you simply don't want in currency stuff.
quidquid Latine dictum sit altum videtur
So currency is as accurate as possible for each maths operation. But over several it runs a higher risk of inaccuracy it seems.
I still think fp is probably more accurate overall. You don't lose bits off the end quite as easily.
Just MHO.
For big things floating point (esp double precision) is okay. An old app I wrote (long ago when dinosaurs and Qbasic ruled
) for finance companies could deal with heavy duty reports for govt (and their scientific calculator wielding scrutineers). It could calculate interest, projections, rule of 72 and etc to the day (or hour if needs be) for thousands of clients with millions of dollars involved in some accounts. And not get the govt on the lender's (and therefore my) back.
Mind you, I am digressing and this heading into discussion/debate territory.
I still think fp is probably more accurate overall. You don't lose bits off the end quite as easily.
Just MHO.
For big things floating point (esp double precision) is okay. An old app I wrote (long ago when dinosaurs and Qbasic ruled

Mind you, I am digressing and this heading into discussion/debate territory.
Dare2 cut down to size
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...
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
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )