- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Once I almost did something similar. It was the first time I was stoned and my friends challenged me to write a program that draws a circle. The circle part was easy, but I couldn't for the life of me neither find nor remember which function in Delphi can be used to convert floats to integers. So I started to write a function that converts a float to string, finds the decimal point, cuts off the fraction and converts the string to integer. But, of course, converting a float to string proved to be an equally challenging task :)
And then after 25 minutes of such creative process, a thought came to my head: what if the function is named something like FloatToDecimal :)
Admin
Be honest folks ...
Each of us dit (in ancient times) a implementation like that [;)] ... *hrhrhr*
Admin
Holy crap, I thought it was only VB6 and VBScript that did bankers' rounding. I just tested it in C# and it does in fact do it there too. Looks like a company I used to work for may get screwed out of a few cents every now and then. ;)
Where is the flag to switch to another rounding method? I did some cursory searching and couldn't find it in any of the Math.Round overloads.
Admin
Among all the other minor and major WTFs in this code, it seems like a pretty subtle issue that he always rounds the same way. A good rounding function:
This avoids introducing a bias into your data by distributing the rounding jitter evenly to both directions.
But of course, with all the other ways in which this code his wrong, it’s no surprise that the mathematical subtleties of rounding correctly escaped this warm body.
Admin
Ah, I see the issue has been commented on in the meantime.
Admin
That looks pretty terrible. Sorry.
Admin
If you want that kind of rounding, sure but if you want 'standard' rounding, I don't see why you would want to not fufill the requirements.
Admin
719 / 4 = 179.75
179.75 + 3 = 182.75
In this case 3.719 is equivalent to 3 719/4 (3 and 719 quarters). See? The intFractions number is the denominator of a fraction, the decimal part of the number which is passed into Round_price() is the numerator.
Admin
Maybe my numbering skills have left me, but wouldn't this kind of system create clusters and gaps in your data, and create bias rather than distributing evenly? Using that rule, no rounding would ever produce an odd number!
Rounding -0.6 to -1 is:
A) not "rounding to 0" but, in that example, rounding away from 0;
B) totally correct, since -0.6 is closer to -1 than to 0. Closest whole number.
Admin
It's only fives that get rounded to the nearest even.
Admin
Round-half-up produces an upward bias on the data. For example:
4 = 2.5 + 1.5
round-half-up: 2 + 3 = 5.
bankers rounding: 2 + 2 = 4
The reason is that there are 9 roundable digits. 1...9 In round-half-up rounding, 5 round up and 4 round down. This increases the probablility that at the end up the day, the sum of all the accounts will be greater than the total you started with.
Banker's rounding removes this bias and makes it more likely that won't happen.
Admin
Wow! I'm glad he wrote it, I'm not sure I'm adept enough to do it myself...
www.lamecode.com
Admin
I declare constants as constants and variables as variables.
The problem with global variables is that they can be changed anywhere. Constants do not change. That is why they are called constants.
Sincerely,
Gene Wirchenko
Admin
3/1000 s 300,000,000 times comes to 90,000 seconds. That is just over a day. Maybe your realtime apps do not have as strict of timing requirements as others' do?
Sincerely,
Gene Wirchenko
Admin
CLng() uses symmetric rounding, and there is a good reason for it. It helps cut down the bias in rounding.
Unfortunately, I could not find it documented HOW it rounded. Page after page of Microsoft docs simply stated that rounding rounded.
The rounding is applied in more than just CLng(). Try 17.5\2.5. The answer is 9, because 17.5 is rounded up to 18 and 2.5 is rounded down to 2.
Sincerely,
Gene Wirchenko
Admin
You misunderstand. 0.0003 seconds per 300,000,000 method calls or 0.00000000001 [1*10^-11] seconds per method call.
Admin
I haven't followed baseball that seriously in quite a while (I think before the last time the Jays won the Series), but...since when are there 'thirds' of innings?
Is this the new menage-a-trois baseball?
Admin
#include<time.h>
#include<stdio.h>
int g = 0;
int parm(int a){ return a+1; }
int global() { return g+1; }
int main()
{
int a = 0;
int i;
time_t start, end;
start = time(0);
for(i=0; i<300000000; i++) {
parm(a);
}
end = time(0);
printf("time for parm: %i secs\n", end-start);
start = time(0);
for(i=0; i<300000000; i++) {
global();
}
end = time(0);
printf("time for global: %i secs\n", end-start);
return 0;
}
Result:
% ./a.out
time for parm: 20 secs
time for global: 9 secs
Over twice as fast. The point is, it's worth knowing about these things if you want a faster program.
There are two rules for when to optimize:
Admin
Ahhh... nothing like a GOSUB. :)
Admin
What if you did a fair test where you set g on each call? Did you consider the compiler may have optimized away the global version of the method because g never changes?
Other issues: How many times did you run this? Running benchmarks like this in tandem will often give skewed results. What if your anti-virus scanner kicked in during the second loop? Also I've seen so many cases where switching the order of the loops will completely change the results.
0.00000003 vs. 0.000000066...
You find that to be significant?
And ignoring that, your numbers here are meaningless because your method is trivial. Most methods actually do something more than increment an int. Moreover, most apps are going to do a lot more than increment an int 300 million times and ignore the results on each call. If that's the kind of app you are writing, then maybe it matters. Otherwise, it's not going to matter.
Admin
Each out recorded yields one-third of an inning pitched for whoever is pitching. It allows ERA to be figured properly when a pitching change happens mid-inning.
Admin
you are not guaranteed that the decimal separator will be a period, so this code breaks on a lot of international settings
Well, if you are using the US way of quoting prices, you sure don't care about non-English users of the application.
Admin
The snippet in this post is VB6 which also does banker's rounding. I've not been able to find any switches that change this behavior in .NET, so please post them if you know. I've found myself implementing a custom round function a number of times, usually in situations where the numbers have to match something (spreadsheet, mainframe, etc.) that uses a different rounding method, usually arithmetic. MS has a custom VB6 Round function that they released in a KB awhile back that handles a number of different rounding types - converts to .NET fairly easily. Obviously, whateverTF this guy is trying to do here doesn't appear in the article...
http://support.microsoft.com/?kbid=196652
Admin
Shouldn't it be sixths, then?
Admin
Oh. I thought you meant per call. BTW, that is 0.003 not 0.0003.
Sincerely,
Gene Wirchenko
Admin
20 seconds? Dude, are you running that test on an abacus or what?! ;-) Here's my implementation of your test (split into two apps): and
Note how I use the return value (even though the test always fails) just to make sure the compiler doesn't do anything tricksy with unused data. On an Athlon 2Ghz, the global version runs in 1.66 seconds and the parameterised version in 1.88, so about 0.2 seconds difference. That's unoptimised. With the -O3 flag, the respective times are 0.296 and 0.299 seconds, so still a difference of 3/1000ths over the 300,000,000 calls.
Admin
If someone knows how to use pre-written functionality in .Net (c#) to do arithmetic rounding, by all means, tell us.
I have looked for it and could not find it. MS has implemented it for other stuff like excel, but not .net AFAIK. It does seem odd that they wouldn't, though.
I just ended up implementing my own round. Apparently, no one ever noticed it was doing bankers rounding by default. Several rounding bugs were in the bug tracker for a while...
Admin
It would be, but an "inning pitched" is actually a half-inning. Kind of like how "batting average" isn't an average at all (it's a percentage expressed as a decimal).
Admin
If you were getting data in string form, it would be provided by a US service, so that would be correct. But you're getting (into the function) a float and converting it to a string, using your own string format. That's something a Canadian brokerage might well have to do with US investments, and in the Québec/Moncton/Sudbury office, the settings on a given machine might well be French.
At any rate, it's just a side effect of the initial dumb decision to take data in a numeric format and convert it to a string for the purpose of doing a math operation on it. (That raises another issue: what if a floating-point bug causes a 102.17 to appear as 102.1699999999?)
Admin
Then you might define a "Close Enough" operator, in addition to ==, <=, >= etc.
Or so I've heard.
Admin
Context, man! In this function, your 102.17 (which should, of course, become 102.53125) would spit out 53'125'101.96875!
Admin
I disagree. I think the original dumb decision is to try and shoehorn 2 distinctly different data types into a single representation, without thinking which representation is the most appropriate (or, indeed, thinking at all)
A better approach overall might well be to use an abstracted, hopefully exact[1], representation of values internally, and to convert to and from this as needed. Of course that's a bit[2] slower.
The locale arguments still stand, of course.
Simon
[1] See http://support.microsoft.com/kb/q279755/ for a dumbed down explanation of floats for VB programmers, note "if accuracy is important to your calculation, use the Decimal data type" [2] for varying values of "a bit"
Admin
Admin
Right, using "inning" to mean half-inning. When "inning" means full inning (and I must deny US responsibility for this, as cricket has even more impressive confusion on the matter--there, the phrase "2nd innings" is ambiguous!), the pitcher always changes at the middle of an inning, not because of a substitution, but because the other team is now at bat [H]
Boy, has this become a funny digression.
Admin
Lots and lots of WTFs in that code, but I particularily like the way he passes a floating-point number with binary mantissa into the function, performs decimal rounding on it, and returns the result as a Double (with binary mantissa again), which cannot even store most decimal fractions losslessly. Curious results like
Round_price(Round_price(x)) != Round_price(x)
are practically guaranteed.Admin
If it takes you a CS professor to figure out that global variables are pure evil, you:
a) had a lot of luck and never got burned
b) are rather resistant to learning
Hate to say it, but global variables don't only make hard to maintain and even understand, they automagically turn any code that uses them - whether directly or indirectly - into a non-reentrant mess. Now some coders may instinctively reply "My code doesn't use threads.", to which I respond:
a) Not yet.
b) Non-reentrant code doesn't mess with multi-threading alone, it also messes with recursion.
Some people on this board have suggested that there was a contradiction between "global variables are evil" and the hype surrounding the singleton pattern. But they are fundamentally wrong. Global variables encapsulate, or let's say merely contain, plain old data. Singletons - if used properly - encapsulate behaviours. That's a difference like night and day, and anyone who uses classes as more than just containers for public fields can confirm that.
Of course, it is possible to abuse singleton in a way that's no better than the use of global variables, but it's for instance easy to make the methods of a well-designed singleton class thread-safe or reentrant, or to alter/exchange its implementation without affecting the rest of the application (this is an important aspect of maintainability). Try that with a global variable.
Admin
The loops don't do anything, so a clever compiler might opt to eliminate them entirely. Which is actually exactly what GCC 3.4.4 does at -O3, at least judging from the 0 seconds execution time in both cases I get on this machine.
The time measurement is rather crude, too - it uses 1 second granularity and "real time", not "process (user) time". I had to change
i
to anunsigned int
and let both loops count to 4000000000u (4 billions) to actually see a difference at-O0
on the Athlon XP 2800+ I use here.But even then, with optimizations disabled, it's only about 10% - 32 vs. 29 seconds. However, please understand that I can't grant you even that small victory :o). That's because if you do have a function where function call overhead really matters, then by all means you should
inline
it and gain more performance than you would by using silly and unmaintainable global variable hacks.Admin
Having a central driver makes all of that simply "globalData.client.lobby.tableList.tables[0].seat[0].user = new user"
And yes, I actually have code like that.
Eep! A single line with intimate knowledge of 6 other classes or structures. Low coupling is the goal, not high.