• blarg (unregistered) in reply to Brian White
    Brian White:
    hoodaticus:
    Brian White:
    blarg:
    lolwtf:
    blarg:
    for those complaining about float for monetary values, how would you suggest storing $0.018372 ?

    Not all applications are built for airline tickets and groceries you know...

    As either the integer 18372 (or 183720 if you deal in hundred-thousandths of a dollar, etc) or the value 0.018372 represented by something more precise than floating-point.

    ok, now lets say the next number has an extra digit - are you going to re-write all your code because you came up with a ridiculously non-flexible design?

    Saying "something more precise...." is a complete cop out. Either name what this "something" is, or accept that you don't have the answer.

    I work in finance, and valuing things to numerous decimal places is common place. floats work fine for this purpose.

    Really? I wonder why every major RDBMS has a money type in that case.

    If you are in finance and evaluating things to an arbitrary number of decimal places, then yes, floats are fine.

    So do you invoice people for $101,491.3954928211 on a regular basis? And then hound them if they are .000000000001 cents short of what they owe? Keeping track of sub-penny amounts seems pointless when you can only be paid in multiples of pennies. It just gives rise to a situation where sum(what we were owed) <> sum(what we were paid) even when everyone has paid you everything you asked for. What do you do with the incremental difference? Do you carry it forward to the next month and try to invoice for it then, hoping that the customer won't notice you are invoicing them for 1 penny more than they see on their monthly usage report?

    not sure if you are trolling or just stupid.

    Unless you have a RDBMS which runs java code, your previous comment was completely irrelevent (yes, we are discussing java).

    Your talk of invoicing customers suggests that you are still in the fantasy world where money and cash are the same thing.

    Looking at NASDAQ right now, I can see that Intel shares are going for $19.8559, you know why that is 4dp? because even small variations actually matter. If you start writing systems which calculate fair price to 2dp only, you are going to bankrupt your company pretty damn quickly. If you don't think that potentially losing hundreds of millions of dollars is a big deal, that is your choice - but most people would say you are wrong.

  • Brian White (unregistered) in reply to blarg
    blarg:
    Brian White:
    hoodaticus:
    Brian White:
    blarg:
    lolwtf:
    blarg:
    for those complaining about float for monetary values, how would you suggest storing $0.018372 ?

    Not all applications are built for airline tickets and groceries you know...

    As either the integer 18372 (or 183720 if you deal in hundred-thousandths of a dollar, etc) or the value 0.018372 represented by something more precise than floating-point.

    ok, now lets say the next number has an extra digit - are you going to re-write all your code because you came up with a ridiculously non-flexible design?

    Saying "something more precise...." is a complete cop out. Either name what this "something" is, or accept that you don't have the answer.

    I work in finance, and valuing things to numerous decimal places is common place. floats work fine for this purpose.

    Really? I wonder why every major RDBMS has a money type in that case.

    If you are in finance and evaluating things to an arbitrary number of decimal places, then yes, floats are fine.

    So do you invoice people for $101,491.3954928211 on a regular basis? And then hound them if they are .000000000001 cents short of what they owe? Keeping track of sub-penny amounts seems pointless when you can only be paid in multiples of pennies. It just gives rise to a situation where sum(what we were owed) <> sum(what we were paid) even when everyone has paid you everything you asked for. What do you do with the incremental difference? Do you carry it forward to the next month and try to invoice for it then, hoping that the customer won't notice you are invoicing them for 1 penny more than they see on their monthly usage report?

    not sure if you are trolling or just stupid.

    Unless you have a RDBMS which runs java code, your previous comment was completely irrelevent (yes, we are discussing java).

    Your talk of invoicing customers suggests that you are still in the fantasy world where money and cash are the same thing.

    Looking at NASDAQ right now, I can see that Intel shares are going for $19.8559, you know why that is 4dp? because even small variations actually matter. If you start writing systems which calculate fair price to 2dp only, you are going to bankrupt your company pretty damn quickly. If you don't think that potentially losing hundreds of millions of dollars is a big deal, that is your choice - but most people would say you are wrong.

    Shockingly enough, it is possible even in java to represent money without using floating point math. The point of the MONEY datatype in an RDBMS is to establish that money uses fixed point decimals.

    "$19.8559, you know why that is 4dp?" Because MONEY in SQL Server goes out to 4 decimal points? Just kidding, but you apparently didn't read any of my comments about the MONEY data type. In Informix it can go to 16 decimal points or something ridiculous. But it will be FIXED point. This is trivial even using integers. First convert everything to pennies. Then, do you care about more than to the penny? If so multiply by 10 for each extra precision. Then do your math. Then convert back into pennies. You will deal with 20 + 25 instead of 0.1999998999 + 0.249999997999, and your results will be more accurate while being no less precise. I mean literally more accurate. There are times with floating points where two things add together and both are sufficiently off that the result is an entire penny different than what it should be. So use fixed point decimals or int or a money class or something to avoid that.

    "If you don't think that potentially losing hundreds of millions of dollars is a big deal, that is your choice - but most people would say you are wrong." Yes... that's my point exactly. I only mentioned invoicing customers because I've written several systems like that, and you really notice off by a penny errors there quickly. You notice it quickly on contract entry screens too that you cannot sanely represent a per transaction price as 3.478282828282828282828, or a 10% discount as 1.333333333333, it needs to be a fixed point value that you can simply multiply by number of transactions to find a total.

  • Neil (unregistered)

    public static bool isSafelyEqual(Object obj1, Object obj2) { try { return obj1.equals(obj2); catch (Exception e) { return obj1 == obj2; } }

    Just in case obj1's equals is missing a null-check, or perhaps an instanceof.

  • baa (unregistered) in reply to powercf
    powercf:
    The Date comparisons in #1 look fine to me also. I believe a Java Date includes hour, minute, second also. The comparison function is just comparing the year, month, day

    Java Date is a moment in time, up to the millisecond. If you want to represent a less formal concept, like an expected arrival date for a shipment, and are working with different timezones, using Java's Date class to represent that information will lead to pain and suffering, as you can get bitten by daylight savings, timezone representations, and all kinds of other things that, conceptually, we'd typically not worry about.

  • baa (unregistered) in reply to Brian White

    In Java, best practices for most industries involving money include working with BigDecimal for currencies. It's nowhere near as fast as working on basic types, but it is a far better representation when your main concern is accuracy. Then, you have rounding functions at the appropriate places as dictated by business rules.

    This even works for, say, a POS register: Taxes, discounts and all that can be then rounded sale-wide, with the rounding being applied to a single penny in a single item, instead of having to round per item, which in case of multiple discounts and a tax or three, could lead to very different results if you buy, say, an item with a $100 base price over buying 100 $1 items.

  • Brian White (unregistered) in reply to baa
    baa:
    In Java, best practices for most industries involving money include working with BigDecimal for currencies. It's nowhere near as fast as working on basic types, but it is a far better representation when your main concern is accuracy. Then, you have rounding functions at the appropriate places as dictated by business rules.

    This even works for, say, a POS register: Taxes, discounts and all that can be then rounded sale-wide, with the rounding being applied to a single penny in a single item, instead of having to round per item, which in case of multiple discounts and a tax or three, could lead to very different results if you buy, say, an item with a $100 base price over buying 100 $1 items.

    I don't think this is at all sane. Let's say you accumulate 3 chunks of .1 cent, from a state, city, and gift tax, and then at the end of the sale transaction you round the total up 1 full cent higher. What do you do with that penny? Which tax item do you apply it to? Do you send it to the city? If so the state will be mad. Do you send it to the state? If so the city will be mad. You cannot split it, so you have to leave one of them out. Do you pocket it a la Office Space? Not to mention that you are describing a POS which will print out a series of tax items where if the customer checks the math on one of the tax items they will get a different number than the one you show. So in addition to angering either the city or the state, you are also going to anger your customer.

    Items are sold in multiples of pennies only. Taxes are collected in multiples of pennies only. I am seriously surprised that either of these statements is controversial.

  • (cs) in reply to too_many_usernames
    too_many_usernames:
    Unless they changed it, the C standard covers this by explicitly stating that pointers (and only pointers) set to the literal value 0 always represent the null pointer, even if the OS has 0 as a valid address.

    In C, assigning a null pointer constant (it need not be a literal character "0") to a pointer-type variable sets that variable to the null pointer representation. Changing that would break nearly all existing C code, so no, it hasn't changed.

    However, it has nothing whatsoever to do with how the OS treats addresses, as far as the C language (ie, the standard) is concerned. The C language is described in terms of implementations of a virtual machine. In most C implementations, C pointers happen to be machine addresses (and the common OSes for those machines typically also deal in machine addresses). But it's not the OS that determines a C implementation's null pointer representation.

    too_many_usernames:
    Even in C, you're not supposed to deal with the underlying format of pointers; you're just supposed to use pointer math on the pointers provided by the OS.

    You're welcome to inspect the representation of pointer objects by treating them as arrays of unsigned char, just as you can with any other object in C. Of course the results are implementation-dependent. And again the OS has nothing to do with it.

    too_many_usernames:
    To be honest, though, I don't know if evaluation of a pointer as a Boolean implicitly compares it to the literal 0 (and so always compares to the true null pointer) or if it treats it as an integer type.

    The abstract machine defined by the C standard does neither: when a pointer-type object is evaluated in a Boolean context, it evaluates as 0 (false) if null, and 1 (true) if not null. Thus in:

    int obj, result, *a = 0, *b = &obj; result = (!!a) + (!!b);

    result will have the value 1.

    By the way, some posters here seem to have problems understanding the difference between NULL, null pointers, and a null pointer constant in C. A null pointer constant is a constant integer expression that evaluates to 0, or such an expression cast to a pointer type. NULL is a macro, defined by the standard headers stdlib.h and stdio.h, which expands to a null pointer constant; the standard requires that it be a bare constant integer expression, or one cast to void*. There's no such thing, in C, as a "NULL pointer".

  • (cs) in reply to Eisentein
    Eisentein:

    x = y // "y" is assigned to "x" x == y // "y" is logically equivalent to "x", can convert types if required x === y // "y" is identical to "x", no conversion of types allowed x ==== y // "y" is composed of the same electrons as "x" x ===== y // "y" ==== "x" and across all space/time continua

    x ====== y // always false; assumes a metaphysics where two entities with all the same attributes are nonetheless distinct

  • buddha (unregistered) in reply to MichaelWojcik
    MichaelWojcik:
    Eisentein:

    x = y // "y" is assigned to "x" x == y // "y" is logically equivalent to "x", can convert types if required x === y // "y" is identical to "x", no conversion of types allowed x ==== y // "y" is composed of the same electrons as "x" x ===== y // "y" ==== "x" and across all space/time continua

    x ====== y // always false; assumes a metaphysics where two entities with all the same attributes are nonetheless distinct

    x ======= y // you have reached enlightenment

  • blarg (unregistered) in reply to Brian White
    Brian White:
    blarg:
    not sure if you are trolling or just stupid.

    Unless you have a RDBMS which runs java code, your previous comment was completely irrelevent (yes, we are discussing java).

    Your talk of invoicing customers suggests that you are still in the fantasy world where money and cash are the same thing.

    Looking at NASDAQ right now, I can see that Intel shares are going for $19.8559, you know why that is 4dp? because even small variations actually matter. If you start writing systems which calculate fair price to 2dp only, you are going to bankrupt your company pretty damn quickly. If you don't think that potentially losing hundreds of millions of dollars is a big deal, that is your choice - but most people would say you are wrong.

    Shockingly enough, it is possible even in java to represent money without using floating point math. The point of the MONEY datatype in an RDBMS is to establish that money uses fixed point decimals.

    "$19.8559, you know why that is 4dp?" Because MONEY in SQL Server goes out to 4 decimal points? Just kidding, but you apparently didn't read any of my comments about the MONEY data type. In Informix it can go to 16 decimal points or something ridiculous. But it will be FIXED point. This is trivial even using integers. First convert everything to pennies. Then, do you care about more than to the penny? If so multiply by 10 for each extra precision. Then do your math. Then convert back into pennies. You will deal with 20 + 25 instead of 0.1999998999 + 0.249999997999, and your results will be more accurate while being no less precise. I mean literally more accurate. There are times with floating points where two things add together and both are sufficiently off that the result is an entire penny different than what it should be. So use fixed point decimals or int or a money class or something to avoid that.

    "If you don't think that potentially losing hundreds of millions of dollars is a big deal, that is your choice - but most people would say you are wrong." Yes... that's my point exactly. I only mentioned invoicing customers because I've written several systems like that, and you really notice off by a penny errors there quickly. You notice it quickly on contract entry screens too that you cannot sanely represent a per transaction price as 3.478282828282828282828, or a 10% discount as 1.333333333333, it needs to be a fixed point value that you can simply multiply by number of transactions to find a total.

    confirmed - you weren't trolling..

  • Mike (unregistered)

    The code probably was clearly based on:

    http://www.javapractices.com/topic/TopicAction.do?Id=17

    ... which is based on Joshua Bloch's must-read book, "Effective Java".

    Only the bad/broken/redundant additions to the class are a WTF.

  • Sheriff (unregistered)

    Reminds me of the day a colleage at work explained to me that in PHP, comparison using === was "better" than plain ol' ==.

    No mention of the concept of identity, just "better".

    Captcha: valetudo: a TODO big as a whale?

  • Anon (unregistered)

    TRWTF is that

    isEqual(null, null) returns true isNotEqual(null, null) returns true

    that is,

    isEqual(null, null) == isNotEqual(null, null) == notEqual(null, null)

  • (cs)

    Why for the love of god would anyone go out of their way to use the java.util.Calendar class in their code... especially when the Date class will actually do what they want.

  • methinks (unregistered) in reply to blarg
    blarg:
    for those complaining about float for monetary values, how would you suggest storing $0.018372 ?

    Not all applications are built for airline tickets and groceries you know...

    You obviously do not in the least understand the problem.

    As others have already done all the work to explain this in simple terms, here is a link:

    http://www.javaranch.com/journal/2003/07/MoneyInJava.html

  • blarg (unregistered) in reply to methinks
    methinks:
    blarg:
    for those complaining about float for monetary values, how would you suggest storing $0.018372 ?

    Not all applications are built for airline tickets and groceries you know...

    You obviously do not in the least understand the problem.

    As others have already done all the work to explain this in simple terms, here is a link:

    http://www.javaranch.com/journal/2003/07/MoneyInJava.html

    On the contrary, I do understand the problem very well. I am familiar with binary approximations of decimal numbers. This was the cause of a very frustrating bug I had to solve several years ago (unrelated to money). BigDecimal is a good solution. You are the first to suggest it.

    Choosing an integer and multiplying by a factor of 10 is a horrible suggestion, hence my disagreement with others.

  • Brian White (unregistered) in reply to blarg
    blarg:
    methinks:
    blarg:
    for those complaining about float for monetary values, how would you suggest storing $0.018372 ?

    Not all applications are built for airline tickets and groceries you know...

    You obviously do not in the least understand the problem.

    As others have already done all the work to explain this in simple terms, here is a link:

    http://www.javaranch.com/journal/2003/07/MoneyInJava.html

    On the contrary, I do understand the problem very well. I am familiar with binary approximations of decimal numbers. This was the cause of a very frustrating bug I had to solve several years ago (unrelated to money). BigDecimal is a good solution. You are the first to suggest it.

    Choosing an integer and multiplying by a factor of 10 is a horrible suggestion, hence my disagreement with others.

    The MONEY type I mentioned in the DB is a fixed point decimal. I don't do Java, didn't know there was a direct equivalent. But however you represent it, accumulating fractional parts of pennies through many sub-items in a transaction and then rounding at the end is a horrible idea, and one that only occurs to people because they don't constrain the possible values for a line item to a real amount, which wouldn't even occur to you if you were doing math with ints. Was it you who mentioned a stock being $84.3817? That of course is only an approximation. You cannot by one stock for $84.3817. You will pay $84.38 or $84.39. You could buy 100 stock for $8438.17, giving an average price per stock of $84.3817, but in that case all you really have is a definite price for 100 stocks, and an equation that describes an approximation of the price of one stock.

    Now, is int crazy for money? No, not at all. What does http://www.javapractices.com/topic/TopicAction.do?Id=13 say?
    "Representing money : * use BigDecimal, int, or long (BigDecimal is the recommended default) * the int and long forms represent pennies (or the equivalent, of course) * BigDecimal is a little more inconvenient to use, but has built-in rounding modes * double or float are not recommended, since they always carry small rounding differences"

    The especially interesting comment to me is "the ROUND_HALF_EVEN style of rounding introduces the least bias. It is also called bankers' rounding, or round-to-even. " Which is hilarious, because I had some asp code that i struggled to get to be in synch with some java code, because vbscript does that automatically, and the java code (presumably poorly written) did not, it always rounded .885 up when it could go either way.

  • Jonathan (unregistered)
       /**
        * Compare two objects for equality when both objects are potentially null. 
        */
       public static boolean dateAreEquals(Date obj1, Date obj2){
          //Not optimized. Only layout like that for clarity.
          if(obj1==null && obj2 == null){
             return true;
          }else if (obj1!=null && obj2==null){
             return false;
          }else if (obj1==null && obj2!=null){
             return false;
          }else{
              Calendar c1 = new GregorianCalendar();
              c1.setTime(obj1);
              Calendar c2 = new GregorianCalendar();
              c2.setTime(obj2);
              if(c1.get(Calendar.YEAR)==c2.get(Calendar.YEAR) &&
                 c1.get(Calendar.MONTH)==c2.get(Calendar.MONTH) &&
                 c1.get(Calendar.DAY_OF_MONTH)==c2.get(Calendar.DAY_OF_MONTH)){
                  return true;
              }else{
                  return false;
              }
           }
    

    }

    In C:

       /**
        * Compare two objects for equality when both objects are potentially null. 
        */
       int dateAreEquals(struct Date *obj1, struct Date *obj2)
       {
          switch ((obj1 == NULL) + (obj2 == NULL))
          {
              case 2: /* Both NULL */
                 return true;
              case 1: /* One NULL, one non-NULL */
                 return false;
              case 0: /* Both non-NULL */
                 return (obj1->Year == obj2->Year)
                     && (obj1->Month == obj2->Month)
                     && (obj1->Day == obj2->Day);
           }
    
           return false; /* Dead code, but probably won't be detected by compiler */
       }
    
  • Karagee (unregistered)

    It reminds me of the behaviour of '==' operator in javascript ...

Leave a comment on “The Qualities of Equality”

Log In or post as a guest

Replying to comment #:

« Return to Article