• D2oris (unregistered) in reply to ParkinT
    ParkinT:
    Toodle:
    Cyrus:
    Cents doesn't means cents...

    Makes cents I suppose. rimshot

    sniffs and wrinkles his nose

    That comment really has a bad cent!

    Fortunately it is not old. It has some currency!
    You sirs, are king amonst men

  • Claxon (unregistered) in reply to Not So Bad
    Not So Bad:
    Old school game programmers will recognize this as a "fixed point" technique; representing floats as integers, so you might have 16.16 (16 bits for the integer part, 16 bits for the floating point part). Really handy back when floating point units weren't quite as fast and DOOM ran without a 3D card!

    Oh, Not just old school. Those of us concemned to an eternity of J2me Game programming are also painfully familiar with Fixing Points (and hanging on for dear life). Those "Old schoolers" dndn't know how lucky they were, when floats were just slow, as opposed to being spat out by the compiler as an invalid type.

  • Jon Skeet (unregistered) in reply to KG
    KG:
    Actually, I'm pretty sure the C# compiler performs escape-analysis (I think that's what it's called). Basically, if an object's reference leaves a function, it is allocated on the heap. Otherwise, it is allocated on the stack.
    No, it doesn't. Instances of classes are always allocated on the heap. I have heard of escape analysis being performed by the C++/CLI compiler, but I wouldn't like to claim that it really does it, or exactly what the effect is on the generated IL even if it does.

    Don't forget that most of this isn't decided by the C# compiler, but by the CLR.

    KG:
    Of course, declaring Money as a struct guarantees it's always allocated on the stack.
    Again, no. It will be allocated on the stack if the expression it's the value of is on the stack - a local (non-captured) variable, for instance, or part of a local (non-captured) variable which is also a value type.

    However, if you have something like:

    class Product
    {
        Money price;
    }

    then "price" will always be on the heap, as it's part of a reference type. Likewise any static variable of type "Money" will also be on the heap.

    See http://pobox.com/~skeet/csharp/memory.html for more details.

    Jon

  • Matt (unregistered)

    Can't you see? It all makes perfect sense. Expressed in dollars and cents, (hundredths of a cent and thousands of a cent), pounds, shillings, and pence.

  • Vroomfundel (unregistered) in reply to KG
    KG:

    Of course, declaring Money as a struct guarantees it's always allocated on the stack.

    Not if it is a field in a reference type.

  • Vroomfundel (unregistered) in reply to Jon Skeet
    Jon Skeet:

    ...

    See http://pobox.com/~skeet/csharp/memory.html for more details.

    Jon

    Jon, you rule! You never miss an opportunity to point the "incorrect oversimplification" :-)

  • (cs) in reply to ParkinT
    ParkinT:
    Toodle:
    Cyrus:
    Cents doesn't means cents...

    Makes cents I suppose. rimshot

    sniffs and wrinkles his nose

    That comment really has a bad cent!

    Fortunately it is not old. It has some currency!

    Euros bad as him. Sterling effort I suppose, but I should Pound all three of you into the ground. Yen we'll get back on topic. Because Franc-ly, money puns are obsolete. And I've lost my notes.

  • A N Other (unregistered) in reply to knock it off...
    knock it off...:
    So, best bet is using an integer type and treat all values as ten thousandths of a Euro. Placing the decimal point is only necessary for user interaction and is moreover trivial.

    Welcome to a basis point my friend

  • Reon (unregistered) in reply to ParkinT

    You guys make me mo-ney

    [moan]

  • Cloak (unregistered) in reply to merreborn
    merreborn:
    Despite that, he was able to sneak in a little change – er, adaptation. price_in_cents became a DECIMAL and the system became a little saner.

    Were alex working in MySQL 4.1, this would have been a horrible mistake. All operations on MySQL's DECIMAL (arbitrary precision) type are done with float operators. So you'll have all the standard floating point errors.

    For databases without arbitrary precision math, storing currency in an integer is the right choice.

    The problem with money is that it can become quite a lot very fast. Given that the INT column was already used with cents and later with hundreths we loose 4 orders of magnitude for what the maximum could be. In SQL Server you would end up with a max of + or - $200,000 which is not sooo much and could easily be exceeded. So a new INT column should be used, 1 for the $ one for the cents and their fractions.

  • (cs) in reply to Grovesy
    Grovesy:
    Harrow:
    snark:
    I got an idea. Use some of the bits for the matissa and some for the exponent. I think I'll call it a gliding point.
    Not enterprisey enough. I'm gonna use some of the bits for the exponent, some for the mantissa part, and some for the radix. That way, I can have exact fraction precision in any number base. Need to store $0.0303? No problem: radix=10, exp=-4, fract=303.

    Yes, you may well laugh now. But when beings from a superior civilization on another planet come 175,000 light-years to bank their money with us, and happen to use base 12, and are VERY particular about roundoff errors, and have great big honkin' scrotum-shrivelin' death ray cannons, then we'll see, hah.

    -Harrow.

    Of course the exponent, mantissa, and radix should be stored in an Xml file, and we need some Factories, Messages, and Commands... Perhaps a Controller as well, and some class with the word 'strategy ' in, I like strategy

    See, this is a clear case of "premature enterpriseyation," as I believe it should be called. There's much, much more that we need to do just with the underlying concept of "money," way before we start to architect the framework.

    For example, who says that real numbers are a sufficient model? I can certainly imagine a use for complex numbers (six columns, or only five if you collapse the real and imaginary radixes!). Store the tax in the "real" part, and the amount left in the "imaginary" part. (Well, that's the way my bank account looks at the moment.)

  • Cloak (unregistered) in reply to Demaestro
    Demaestro:
    I wouldn't have even gone to a decimal.. just store everything in cents. Best design is always store the lowest possible unit.

    You don't need dollars just cents. How many dollars can be calculated based on the amount of cents.

    I do the same for time.. why store hours and fraction of hours.. or minutes and fraction of minutes... when you can store seconds and convert to get either?

    Because of such wisdom we will run into the year 2038 problem.

    http://en.wikipedia.org/wiki/Year_2038_problem

  • OJ (unregistered) in reply to Claxon
    Oh, Not just old school. Those of us concemned to an eternity of J2me Game programming are also painfully familiar with Fixing Points (and hanging on for dear life). Those "Old schoolers" dndn't know how lucky they were, when floats were just slow, as opposed to being spat out by the compiler as an invalid type.

    The practice also lives in DSP programming. Programming for a DSP is so full of low level pain anyway that you don't really notice anything out of ordinary. The only remotely tricky part is when an algorithm needs to slide the decimal point during calculations. Matlab has quite sensible fixed point type that helps a lot.

    Of course there are then those programmers who don't get the whole idea and use powers of ten for decimal. If only the NDA was not there...

  • dbgeek (unregistered)

    well, if Pete was consequent, he ran an update on the prod data, multiplying the values by 10 for each version.

    Let's just hope that was the case.

    Captcha: Eros (yeah thats me)

  • Rob (unregistered)

    When talking about prices in financial applications it's not unheard of to create money types as integers by the cent for type portability (among a few other reasons).

    Problem occurs when you're not actually talking about cents but the abstract cent fractions (which could still be ok if you had all the integers required to calculate the fraction)

  • Mr. Bean (unregistered) in reply to ParkinT

    I guess it depends on how old the application is and what its history is. If it was originally written using a database that didn't have a MONEY data type, using an integer would have been a very sensible option. And if that's what the programmer was used to, he may have done it automatically anyway, even if he was using a DB with a MONEY type.

    In fact, it's just the changes in precision that have caused the problems, and I'll give you bets it was the same management that insisted it was done that way that are still insisting it gets ported without any changes.

    It's worth noting that if this is an application in the financial sector, these banking guys can be very strict about changes to their software. If an application works as required, they will be extremely reticent to change it at all, and if they do authorise a change, every tiniest modification has to be approved and cross-checked in ways that would trusly scare most of us mere mortal programmers.

  • Jon Skeet (unregistered) in reply to Sean
    Sean:
    His solution will lead to a future WTF. Don't use floating point for money.

    At least, don't use a binary floating point type. If you've got a fixed decimal point type (as databases tend to) then that's great; using a decimal floating point type (like System.Decimal in .NET) will avoid most of the problems people run into with binary floating point types.

    Jon

  • alex (unregistered) in reply to gabba

    After working with currency, money, small money, decimal (18,4) , decimal (27,6)!!! and finding it both cumbersome (convert functions peppering stored procs etc) and difficult to maintain consistency across multiple tables/developers we decided when we set about re-writing our risk platform some years ago that all numbers should just be floats. For reporting, where necessary we use the round function, or just format in the client (often Excel).

    We did consider using 'int' for share quantity, but found 2 billion sometimes wasn't enough for some of our positions - I work for a large firm! - so we went for floats here also.

    We are VERY happy we made this decision and recommend it to anyone considering any other approach.

  • scruffy (unregistered) in reply to Not So Bad

    (Not Just the old school'ers matey! DSP and embedded guys are still using fixed point, and embedded c actually has proper base types for it!)

    The scarry thing is that Pete's antics went unnoticed... so Either he was

    • Running bespoke tools that would "fix" the database as such changes were made. (Cripling old versions as he went.)
    • Old records simply weren't used, ("Hello Mr Auditor please abuse me.") or worst of all...
    • The system was spewing crap and no one noticed!
  • Bartman (unregistered) in reply to ParkinT
    ParkinT:
    Toodle:
    Cyrus:
    Cents doesn't means cents...

    Makes cents I suppose. rimshot

    sniffs and wrinkles his nose

    That comment really has a bad cent!

    Fortunately it is not old. It has some currency!

    That last comment was so money!

  • dkf (unregistered) in reply to scruffy
    scruffy:
    * The system was spewing crap and no one noticed!
    That's the one I suspect, especially as the error was likely never more than a cent per transaction and so below the 0.1% level. But even so, handling currency in a floating point representation is "Ewwww!"
  • Edward Royce (unregistered) in reply to ParkinT
    ParkinT:
    Toodle:
    Cyrus:
    Cents doesn't means cents...

    Makes cents I suppose. rimshot

    sniffs and wrinkles his nose

    That comment really has a bad cent!

    Fortunately it is not old. It has some currency!

    And it's multi-user too which means that there's some concurrency!

  • mendel (unregistered) in reply to scruffy

    You assume that Pete's antics went unnoticed. I don't think that's the case. Consider, if you will, the question: what happened to make management so wary of change? Could it have been the experience that whenever they requested a change of Pete in his code, the application started breaking in weird and unexpected places?

    If management requests that Pete update his code to calculate with 4 digit precision, and suddenly the price databases is off, and operators have to check and rekey any prices they use, that (and similar occurences) might make management anxious to avoid changes as much as possible because in their experience changes are costly and prone to bite you in unexpected ways.

    And the only person who could have explained to them why this was so was the person whose job security rested on management never finding out.

  • A Really Rich Guy (unregistered) in reply to alcari
    alcari:
    Carnildo:
    snark:
    Not So Bad:
    Well, the idea isn't so bad. Save a number with the precision you need in a simple integer field. The problem is, there is implied information (level of precision) that wasn't captured in the database.

    Old school game programmers will recognize this as a "fixed point" technique; representing floats as integers, so you might have 16.16 (16 bits for the integer part, 16 bits for the floating point part). Really handy back when floating point units weren't quite as fast and DOOM ran without a 3D card!

    He should have had his class spit out another column that documented the precision. Or, just used the MONEY type provided by SQL. :-)

    That's a neat perf trick of "representing floats as integers".

    Just one question how does one represent the float value 1 X 2e16 in the "fixed point" you describe? Or 1 X 2e-16?

    How often does a company sell something that costs 10 quadrillion dollar?

    Is it okay if I pay for it with 10 1-quadrillion bills?

  • tinkerghost (unregistered) in reply to Cloak

    frighteningly enough, I am working right now on a system that uses floating point math to handle money. One formatting routine marked everything to the left of the decimal as $ and 2 places to the right as cents .... looked good until a-(a/2 +a/2) = 1.38E-12. Took a bit of prying to decipher that the $1.38 error on the list wasn't what it looked like.

    Also javascript is just nasty with it's rounding errors. I think I see more there than in any of the other languages I write in combigned. I have a display right now that works with the same data in 3 different modes, A+B+C=D, A+C+B=D and B+C+A=D+0.01.

    I certainly agree with the 2 column storage for $ & cents (nobody is going to be bothered past int for precision on cents, and bigint will cover all but the biggest trading houses) - however, most of the errors in the WTF system could have been avoided if anyone had thought to do a simple money_field = money_field *10 over the effected tables while rolling out the precision updates (and updated the comments on the money class).

  • Thomas (unregistered) in reply to knock it off...
    If different currencies are required, the currency information has to be kept anyway, thus precision information can be stored as well.

    The only information that need be different is the currency ISO itself. Beyond that, you can easily store amounts used by any currency in the same column of type decimal.

  • Thomas (unregistered)

    Sure, storing data such as this as a floating point would be a huge mistake. Trying to out think the SQL schema designers by using a needlessly complicated application-based solution was an even bigger mistake.

    Clearly storing the value as decimal/numeric was the right solution. In that vein, using the Money type would have also been a mistake IMO. Money is proprietary to various DB systems and can do weird rounding when used for division. That said, had he stored it as Money, it would have been easy to change to decimal as most application layers equate Money to decimal.

    Frankly, the core mistake was the lack of thought regarding data integrity. Attention was only given to application integrity (we hope) and when they discovered an error, the data was hosed. Application developers are generally incompetent when it comes to database design and maintaining data integrity.

  • Fister (unregistered) in reply to KG
    Of course, declaring Money as a struct guarantees it's always allocated on the stack.

    Unless it gets boxed, of course.

  • (cs) in reply to Matt
    Matt:
    Can't you see? It all makes perfect sense. Expressed in dollars and cents, (hundredths of a cent and thousands of a cent), pounds, shillings, and pence.
    Don't send millionths of a cent, God don't want small potatoes.
  • Gregtoberfest (unregistered) in reply to ParkinT

    ZING!

  • Senescence (unregistered) in reply to ParkinT

    THERE! I knew if I waited long enough I'd see some good old fashioned male immaturity! Not to mention some really daggy jokes!

Leave a comment on “Price in Nonsense”

Log In or post as a guest

Replying to comment #:

« Return to Article