• Kung-Fu Coder (unregistered) in reply to johnl

    The author was very wise to make the code robust, because everybody knows that just by sampling a character in a string the string itself might suddenly change in lenght (this is also known the Heisenberg Uncertainty Principle amongst Quantum Physicists).

    Hence the: (int)_tcslen(tmpStr)

    The (int) cast is probably there just in case _tcslen() returns a floating-point number. It remains unclear though why the author has not applied the proper rounding scheme there also.

  • (cs) in reply to teedyay
    teedyay:

    We also try to pre-empt their whinges about rounding errors (mostly occurring from our painful 17.5% VAT system), and manage to bring them down from their initial position of "we want everything to add up exactly to the penny in every circumstance, and we don't want to see any fractions of pence" before we write a single line of code.


    Why do you even give them the option? For anything involving VAT, National Insurance or taxes in the UK, HM Revenue & Customs (which is the correct name now - Inland Revenue and HM Customs & Excise merged) has very specific rules about what types of rounding are allowed, and tends to get rather upset if their auditors find you've deviated from the required rounding rules in any way that leads to underpayment (particularly of VAT).

    For NI, for instance, amounts (both the tax amounts and rebates etc.) should generally be rounded up to the nearest whole pound - or at least that's what the last edition of their software developers manual specified last time I checked. For tax/NI it isn't too serious to get it wrong, as the worst thing that happens is that it gets adjusted once the employee hands in their self assessment.

    For VAT, though, there are potential criminal liabilities for the company directors, so it's worthwhile being very careful. The rounding rules that apply are set out in "The Vat Guide", section 17.5 (HMRC Notice 700, available from http://customs.hmrc.gov.uk/channelsPortalWebApp/channelsPortalWebApp.portal?_nfpb=true&_pageLabel=pageExcise_ShowContent&columns=1&id=LIB_PN_VAT ). In general the following applies for VAT invoices, for instance:

    - You EITHER round VAT down to the nearest penny on the entire VAT liable amount on a per invoice basis,
    - OR _down_ to the nearest 0.1p per line item on the invoice
    - OR to the nearest 1p or 0.5p per line item on the invoice

    (Whichever method you choose, you must apply it consistently - you can't use one method for some invoices and another for others unless you particularly want to spend time explaining to an auditor why they should believe you aren't trying to manipulate your way to lower VAT payments)

    Vidar

  • (cs) in reply to Kung-Fu Coder
    Anonymous:

    The author was very wise to make the code robust, because everybody knows that just by sampling a character in a string the string itself might suddenly change in lenght (this is also known the Heisenberg Uncertainty Principle amongst Quantum Physicists).



    Let us endeavour to unite Univeral String theory with Programming String theory.
  • beerwulf (unregistered)
    <FONT size=2>

    I wonder what he'd have done if he needed to work to a variable number of decimal points - or worse - significant figures!

    Here's a C# example of a round function that I came up with when I was bored... using Math.Pow and Math.Log10, but not Math.Round.

    <FONT color=#0000ff size=2>public </FONT><FONT color=#a52a2a size=2>static </FONT><FONT color=#ff0000 size=2>double </FONT><FONT color=#191970 size=2>Round</FONT><FONT color=#006400 size=2>(</FONT><FONT color=#ff0000 size=2>double </FONT><FONT size=2>number</FONT><FONT color=#006400 size=2>, </FONT><FONT color=#ff0000 size=2>int </FONT><FONT size=2>sigFig</FONT><FONT color=#006400 size=2>)

    {

    </FONT><FONT color=#ff0000 size=2>int </FONT><FONT size=2>decPlaces </FONT><FONT color=#006400 size=2>= </FONT><FONT size=2>sigFig </FONT><FONT color=#006400 size=2>- (</FONT><FONT color=#ff0000 size=2>int</FONT><FONT color=#006400 size=2>)(</FONT><FONT size=2>Math</FONT><FONT color=#006400 size=2>.</FONT><FONT color=#191970 size=2>Log10</FONT><FONT color=#006400 size=2>(</FONT><FONT size=2>Math</FONT><FONT color=#006400 size=2>.</FONT><FONT color=#191970 size=2>Abs</FONT><FONT color=#006400 size=2>(</FONT><FONT size=2>number</FONT><FONT color=#006400 size=2>)));

    </FONT><FONT color=#ff0000 size=2>double </FONT><FONT size=2>result </FONT><FONT color=#006400 size=2>= </FONT><FONT size=2>number </FONT><FONT color=#006400 size=2>* (</FONT><FONT size=2>Math</FONT><FONT color=#006400 size=2>.</FONT><FONT color=#191970 size=2>Pow</FONT><FONT color=#006400 size=2>(</FONT><FONT color=#00008b size=2>10</FONT><FONT color=#006400 size=2>, </FONT><FONT size=2>decPlaces</FONT><FONT color=#006400 size=2>));

    </FONT><FONT size=2>result </FONT><FONT color=#006400 size=2>= (</FONT><FONT color=#ff0000 size=2>int</FONT><FONT color=#006400 size=2>)(</FONT><FONT size=2>result</FONT><FONT color=#006400 size=2>+</FONT><FONT color=#00008b size=2>0.5</FONT><FONT color=#006400 size=2>);

    </FONT><FONT size=2>result </FONT><FONT color=#006400 size=2>= </FONT><FONT size=2>result </FONT><FONT color=#006400 size=2>/ (</FONT><FONT size=2>Math</FONT><FONT color=#006400 size=2>.</FONT><FONT color=#191970 size=2>Pow</FONT><FONT color=#006400 size=2>(</FONT><FONT color=#00008b size=2>10</FONT><FONT color=#006400 size=2>, </FONT><FONT size=2>decPlaces</FONT><FONT color=#006400 size=2>));

    </FONT><FONT color=#000080 size=2>return </FONT><FONT size=2>result</FONT><FONT color=#006400 size=2>;

    }

    </FONT>

    <FONT color=#006400 size=2><FONT color=#000000>And yes, I didn't compress it all onto one line, :) - That was reserved for the VB6 version...</FONT>

    </FONT></FONT>
  • (cs)

    Even if the core of these functions is fundamentally wrong, clear comments on why the developer did what he/she did would go a long way to reduce the WTF-edness of this one.
    ----
    Do these functions blow up into funny shapes? Nope, not unless round is funny.

  • (cs)

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank

  • (cs)

    Looks like someone is trying to program too hard!

  • Kiss me, I'm Polish (unregistered) in reply to Rank Amateur
    Rank Amateur:

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank


    Actually numbers make more sense - you can see which version is the latter. Otherwise you would have to comment them somehow in order to know which is better - RoundCorrectIfThisWontWorkThenIGiveUp or RoundCorrectAhIFinallyGotWhatWasWrong or even RoundCorrectFrankSaysThisIsOK
  • (cs)

    Can't correct a mistake with another mistake... and another mistake... and another mistake...

  • (cs) in reply to Kiss me, I'm Polish
    Anonymous:
    Rank Amateur:

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank


    Actually numbers make more sense - you can see which version is the latter. Otherwise you would have to comment them somehow in order to know which is better - RoundCorrectIfThisWontWorkThenIGiveUp or RoundCorrectAhIFinallyGotWhatWasWrong or even RoundCorrectFrankSaysThisIsOK


    No they don't. If version 1 of a function does not work the way its name implies, it should be rewritten - not left in.

    Your suggestion that there is some correctness in appending version numbers to every subsequent correction to the rounding function is akin to the people who make backups of source by creating zip files with the date in the file name instead of using source control software.
  • (cs) in reply to Kiss me, I'm Polish
    Anonymous:
    Rank Amateur:

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank


    Actually numbers make more sense - you can see which version is the latter. Otherwise you would have to comment them somehow in order to know which is better - RoundCorrectIfThisWontWorkThenIGiveUp or RoundCorrectAhIFinallyGotWhatWasWrong or even RoundCorrectFrankSaysThisIsOK

    That's an excellent point. On the other hand, the spec clearly must call for different kinds of correctness for different parts of the code. Why else would he write new functions rather than rewriting Round? Given that, I want my function name to qualitatively describe the correctiptude. Which function number was the one Frank said would work again?

    Hmm... of course the way to have it both ways is to have a global array of function pointers. Just choose your desired correcticacity.

       <FONT face="Courier New" size=2>int roundval = round[correcticacity](initialvalue);</FONT>

    --Rank

  • George H. Ruth (unregistered)

    Given the number of attempts at getting this right, shouldsn't the title of this WTF be, "Rounding Third"?

  • (cs) in reply to Richard Nixon
    Richard Nixon:
    Anonymous:
    Rank Amateur:

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank


    Actually numbers make more sense - you can see which version is the latter. Otherwise you would have to comment them somehow in order to know which is better - RoundCorrectIfThisWontWorkThenIGiveUp or RoundCorrectAhIFinallyGotWhatWasWrong or even RoundCorrectFrankSaysThisIsOK


    No they don't. If version 1 of a function does not work the way its name implies, it should be rewritten - not left in.

    Your suggestion that there is some correctness in appending version numbers to every subsequent correction to the rounding function is akin to the people who make backups of source by creating zip files with the date in the file name instead of using source control software.

    And the award for "joke post taken too seriously" goes to... Richard Nixon!

  • none (unregistered) in reply to guest

    Don't do it in K&R C either.  False is zero, True is any other number.

  • none (unregistered) in reply to guest

    Sorry, forgot quote

             return (int)(number + (number > 0) - 0.5); 
             Don't do this in VB. True is not what you think it is :)

    Don't do it in K&R C either.

  • Fisher (unregistered) in reply to Dagur
    Anonymous:
    There's nothing wrong with using sprintf. In fact that's the recommended way in the perl cookbook.

    I don't get what that guy is doing in that function though.


    PerlFAQ is more fundamental than a cookbooks, isn't it? So, look it (perlfaq4):

    *********
    Rounding in financial applications can have serious implications, and the rounding method used should be specified precisely. In these cases, it probably pays not to trust whichever system rounding is being used by Perl, but to instead implement the rounding function you need yourself.
    *********
  • (cs) in reply to zip
    zip:
    Richard Nixon:
    Anonymous:
    Rank Amateur:

    Round... RoundCorrect.... So the WTF is that he called the third function RoundCorrect2, rather than RoundCorrectReally.

    Coming soon: RoundCorrectNoTrustMeTHISOneWillWork.

    --Rank


    Actually numbers make more sense - you can see which version is the latter. Otherwise you would have to comment them somehow in order to know which is better - RoundCorrectIfThisWontWorkThenIGiveUp or RoundCorrectAhIFinallyGotWhatWasWrong or even RoundCorrectFrankSaysThisIsOK


    No they don't. If version 1 of a function does not work the way its name implies, it should be rewritten - not left in.

    Your suggestion that there is some correctness in appending version numbers to every subsequent correction to the rounding function is akin to the people who make backups of source by creating zip files with the date in the file name instead of using source control software.

    And the award for "joke post taken too seriously" goes to... Richard Nixon!



    I don't believe it was a joke.
  • koning_robot (unregistered) in reply to none
    Anonymous:

    Sorry, forgot quote

             return (int)(number + (number > 0) - 0.5); 
             Don't do this in VB. True is not what you think it is :)

    Don't do it in K&R C either.


    Saying TRUE is any non-zero number is like saying a rectangle is any square.
  • (cs) in reply to Otto

    When writing financial applications, I prefer to use trunc(). Then I take whatever is truncated and add it to my own account.

    I got the idea from Superman 3.

     

    I suspect you were being sarcastic but I know someone who really and truly did that.

     

  • BtM (unregistered) in reply to koning_robot
    Anonymous:
    Anonymous:

    Sorry, forgot quote

             return (int)(number + (number > 0) - 0.5); 
             Don't do this in VB. True is not what you think it is :)

    Don't do it in K&R C either.


    Saying TRUE is any non-zero number is like saying a rectangle is any square.

    There are two related but different concepts here.

    1.  In a Boolean context, all non-zero values evaluate to true, and 0 evaluates to false. 

    2.  The result of any relational or equality expression (<, <=, >, >=, ==, and !=) will always be either 0 or 1, and will always be of type int. 

    The above expression has any number of problems (again, what if number >= INT_MAX), but the expression (number > 0) will always evaluate to either 0 or 1 depending on the value of number. 

  • aj (unregistered) in reply to Otto

    Underrated movie, actually.

  • Anomolous Cowherd (unregistered) in reply to Dagur
    Anonymous:
    There's nothing wrong with using sprintf. In fact that's the recommended way in the perl cookbook.

    Perl is a WTF in itself.  I've never seen a line of Perl that wouldn't qualify for this site.
  • Dagur (unregistered) in reply to Fisher
    Anonymous:
    Anonymous:
    There's nothing wrong with using sprintf. In fact that's the recommended way in the perl cookbook.

    I don't get what that guy is doing in that function though.


    PerlFAQ is more fundamental than a cookbooks, isn't it? So, look it (perlfaq4):

    *********
    Rounding in financial applications can have serious implications, and the rounding method used should be specified precisely. In these cases, it probably pays not to trust whichever system rounding is being used by Perl, but to instead implement the rounding function you need yourself.
    *********


    Uh, that confirms what I said doesn't it? :-/
  • Michael Edenfield (unregistered) in reply to ferrengi
    ferrengi:
    OK,
    So he wrote one function which I cannot follow the logic of and figure out what it does but suffice to say that it can't possibly be a good solution.


    Just in case you're curious, the first function does this:

    1. Convert float to string with just 1 decimal place.
    2. Convert string to int (basically a floor())
    3. Scan string for the first non-digit character.  Presumably the decimal separator
    4. Convert everything the decimal to an integer
    5. If the second integer is less than 4, return the first integer.
    6. Otherwise, return the original value.

    Which brings up at least two WTF's in one function:

    - It fails to round 1.4 -> 1, though it will round 1.3 -> 1
    - If the original value should have been rounded up, it doesn't round AT ALL.

    Round(1.3) -> 1
    Round(1.4) -> 1.4
    Round(1.6) -> 1.6

  • (cs) in reply to vhokstad
    vhokstad:
    teedyay:

    We also try to pre-empt their whinges about rounding errors (mostly occurring from our painful 17.5% VAT system), and manage to bring them down from their initial position of "we want everything to add up exactly to the penny in every circumstance, and we don't want to see any fractions of pence" before we write a single line of code.


    Why do you even give them the option? ...

    Because "that's what matches Sage". Apparently Sage knows all, so if our program agrees with it then everything's OK, it seems.
    Yeah, it all seems a bit dubious, but I take the line that our software's just a tool to produce the numbers they want (though I've just realised that's a tad too close to "I was following orders"...)
  • (cs) in reply to teedyay
    teedyay:
    vhokstad:
    teedyay:

    We also try to pre-empt their whinges about rounding errors (mostly occurring from our painful 17.5% VAT system), and manage to bring them down from their initial position of "we want everything to add up exactly to the penny in every circumstance, and we don't want to see any fractions of pence" before we write a single line of code.


    Why do you even give them the option? ...

    Because "that's what matches Sage". Apparently Sage knows all, so if our program agrees with it then everything's OK, it seems.
    Yeah, it all seems a bit dubious, but I take the line that our software's just a tool to produce the numbers they want (though I've just realised that's a tad too close to "I was following orders"...)


    Ah, well... It's their accountants, company secretary or directors that risk going to jail if they underreport their VAT liabilities, not you, at least as long as it's obvious they knew how the numbers were calculated. Would have to be a pretty serious case for things to go that far though, but if I was you I'd make sure to document who signs off on those decisions :)

    Vidar


  • reuujry (unregistered) in reply to vhokstad

    [U][U][U][U][U]

    vhokstad:
    teedyay:

    We also try to pre-empt their whinges about rounding errors (mostly occurring from our painful 17.5% VAT system), and manage to bring them down from their initial position of "we want everything to add up exactly to the penny in every circumstance, and we don't want to see any fractions of pence" before we write a single line of code.


    Why do you even give them the option? For anything involving VAT, National Insurance or taxes in the UK, HM Revenue & Customs (which is the correct name now - Inland Revenue and HM Customs & Excise merged) has very specific rules about what types of rounding are allowed, and tends to get rather upset if their auditors find you've deviated from the required rounding rules in any way that leads to underpayment (particularly of VAT).

    For NI, for instance, amounts (both the tax amounts and rebates etc.) should generally be rounded up to the nearest whole pound - or at least that's what the last edition of their software developers manual specified last time I checked. For tax/NI it isn't too serious to get it wrong, as the worst thing that happens is that it gets adjusted once the employee hands in their self assessment.

    For VAT, though, there are potential criminal liabilities for the company directors, so it's worthwhile being very careful. The rounding rules that apply are set out in "The Vat Guide", section 17.5 (HMRC Notice 700, available from http://customs.hmrc.gov.uk/channelsPortalWebApp/channelsPortalWebApp.portal?_nfpb=true&_pageLabel=pageExcise_ShowContent&columns=1&id=LIB_PN_VAT ). In general the following applies for VAT invoices, for instance:

    - You EITHER round VAT down to the nearest penny on the entire VAT liable amount on a per invoice basis,
    - OR down to the nearest 0.1p per line item on the invoice
    - OR to the nearest 1p or 0.5p per line item on the invoice

    (Whichever method you choose, you must apply it consistently - you can't use one method for some invoices and another for others unless you particularly want to spend time explaining to an auditor why they should believe you aren't trying to manipulate your way to lower VAT payments)

    Vidar

  • John Hensley (unregistered)

    I can forgive the use of strings, but... ugh, patchwork programming. I see it all the time in interviews. I give someone a programming problem. He writes some code. I point out a failure case. He tacks on an if statement to handle it. I point out another case, etc. No matter how worthless the original code proves to be, a patchwork programmer always thinks about what he can tack on to pass the tests, never how to make the code work.

    Patchwork programmers are fundamentally broken and should not be hired to program, although they may improve in time. They're completely unaware of any connection between the code they write and what it does.

    The worst part is that certain promoters of extreme programming (Robert Martin) are encouraging and teaching such crap.

Leave a comment on “Correcter Rounding”

Log In or post as a guest

Replying to comment #:

« Return to Article