ValC()

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

ValC()

Post by Rook Zimbabwe »

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!!! 8)
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Hroudtwolf
Addict
Addict
Posts: 803
Joined: Sat Feb 12, 2005 3:35 am
Location: Germany(Hessen)
Contact:

Post by Hroudtwolf »

Hi,

Where is the problem ?

Code: Select all

   Debug Asc ("B")
   Debug 'B'
Best Regards

Wolf
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

He's referring to currency as opposed to characters. :wink:
BERESHEIT
Irene
Enthusiast
Enthusiast
Posts: 461
Joined: Thu Oct 04, 2007 12:41 pm

Post by Irene »

Deleted...
Last edited by Irene on Mon Dec 31, 2007 3:03 pm, edited 1 time in total.
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

But... are not all currencies decimal to two places???
X.XX in whatever format?
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Irene
Enthusiast
Enthusiast
Posts: 461
Joined: Thu Oct 04, 2007 12:41 pm

Post by Irene »

Rook Zimbabwe wrote:But... are not all currencies decimal to two places???
X.XX in whatever format?
Why not then simply use floats?

I thought you were thinking of stuff like ValC(25, #PB_Currency_US_Dollar, #PB_Currency_Euro)
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Why not then simply use floats?
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.
Irene
Enthusiast
Enthusiast
Posts: 461
Joined: Thu Oct 04, 2007 12:41 pm

Post by Irene »

Trond wrote:
Why not then simply use floats?
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.
IIRC doubles can be used for representing currency values. Not sure if it is as inaccurate as floats.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Double is more accurate than floats, but integers are 100% accurate.
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Trond wrote:Double is more accurate than floats, but integers are 100% accurate.
In storage, yes. In maths? I am sure you are right, but I need to have it explained.

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
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

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 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.
33.33 in a scaled integer would be EXACTLY 3.33, not 3.3299999237 (actual float precision on 3.33 with two decimals).
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

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:

Code: Select all

a.f = 100000001.0
Debug a - 100000000.0
Doubles do better but have the same problem:

Code: Select all

b.d = 100000000000000001.0
Debug b - 100000000000000000.0
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.
quidquid Latine dictum sit altum videtur
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

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.
Dare2 cut down to size
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

With the currency type you know exactly how much you lose. There no lack of precision, only a lack of which values can be stored. Those values that can be stored can be stored with absolute precision.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

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
( 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... )
Post Reply