- 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
Admin
I like the way it will round 1450 up to 2000 :)
Admin
Alot of people don't realize there's more than one kind of rounding. This appears to be similar to round-to-nearest-even (RNE). There are statistical reasons why you don't always want to round up if the least-significant digit is >= 5, and down otherwise. I've had to implement similar schemes in hardware. Of course there, I wasn't parsing a string, and I was able to reduce the rounding logic to a 3-stage bitwise logic operation.
Admin
private int CalculateGap(int min, int max, int interval)
{
int gap = (max - min) / interval;
int digits = (int)Math.Log10(gap);
double roundingFactor = Math.Pow(10, digits);
return (int)(Math.Round(gap / roundingFactor) * roundingFactor);
}
Admin
No, I don't think this is 'round half even'. It's round 45-50ths up.
And implemented in a completely asinine way.
Admin
Nice solution! Although string manipulation is more efficient...(just kidding)[:P]
Admin
Oops, this is better :)
private int CalculateGap(int min, int max, int interval)
{
int gap = (max - min) / interval;
return (int)Math.Round(gap, 0);
}
Admin
Personally I'd be happier with...
gap % 10 (gap / 10) % 10 (gap / 10 / 10) % 10 (gap / 10 / 10 / 10) % 10
And so on.
Admin
I've seen a lot of string-number handling problems in inexperienced programmers, especially among the managed languages crowd. I think part of the problem lies in the academics at colleges. Scenarios like this one, which are the bread-and-butter of any normal programming job, are usually glossed over because they tend to be language-specific (e.g., math libraries, string handling classes, etc.). Take any kind of data structures classes and they'll spend weeks and weeks going over the abstract stuff like sorting algorithms and big-O notation while spending relatively little time teaching the things that matter in the real world.
Anyway, just an observation from someone who attended CS classes at 3 different universities.
Admin
True; But you're supposed to learn the general/abstract stuff at school.
You're not going to learn about Kruskal and Prim at your first job.
That being said, A programmer in their Junior year should of already done enough projects to build up the experience to handle a problem like this correctly.
Unless they had the exchange student that sits in the front row do all their projects :)
Admin
Seeing how the author didn't check for numbers with 4 or more digits, I don't think he ever had to worry about that scenario.
Admin
My above comment was in response to crlf's comment.
I thought the forum software was going to put the quote in for me. Guess I was wrong.
Admin
Here's a solution to a similar "y-gap" problem that I wrote. It's meant to nearly replicate the way excel auto-scales axes in a graph. It attempts to find the "ideal" spacing of 5-10 divisions on axes, given a min and a max. You may notice one possible WTF in that I used with CString.Format() to round. That's because MFC's math library only has ceil(), floor(), and binary mantissa functions, no "true" rounding functions.
Feel free to tear it apart and make fun of me at your leisure.
Note that much of the class has been snipped. The proverbial meat without potatoes. Huh, apparently I never wrote comments. Have fun!
void CGraphScale::SetMinMax(double dMin, double dMax)
{
m_dActualMin = dMin;
m_dActualMax = dMax;
int i, nMaxIter;
CString strTemp;
double dDiff = dMax - dMin;
if(dDiff>1)
{
strTemp.Format("%.0f",ceil(dDiff));
nMaxIter = strTemp.GetLength();
strTemp = "1";
for(i=0; i<nmaxiter ;="" i="">
strTemp.AppendChar('0');
m_dSpacing = atol(strTemp);
}
else if(dDiff>1e-16)
{
m_dSpacing = 1;
}
else
{
AfxMessageBox("Error: dMax must be greater than dMin.");
ASSERT(true);
return;
}
double dLabel, dMinLabel;
for(m_nDivisions = 0; m_nDivisions<5;)
{
strTemp.Format("%.1e", m_dSpacing);
switch(strTemp.GetAt(0))
{
case '1':
case '5':
m_dSpacing/=2;
break;
case '2':
m_dSpacing/=2.5;
break;
}
if(dMin>=0)
{
for(dLabel = 0; dLabel < dMin; dLabel+=m_dSpacing);
if(dLabel!=dMin)
dMinLabel = dLabel-m_dSpacing;
else
dMinLabel = dLabel;
}
else
{
for(dLabel = 0; dLabel > dMin; dLabel-=m_dSpacing);
dMinLabel = dLabel;
}
m_nDivisions = dDiff / m_dSpacing;
for(dLabel = dMinLabel + m_nDivisions * m_dSpacing;
dLabel<dmax ;="">
dLabel+=m_dSpacing, m_nDivisions++);
}
m_aTickMarks.SetSize(m_nDivisions+1);
for(dLabel=dMinLabel, i=0; i<=m_nDivisions; dLabel+=m_dSpacing, i++)
{
if(abs(dLabel)<1e-16) dLabel = 0;
m_aTickMarks[i]=dLabel;
}
}
</dmax></nmaxiter>
Admin
Still, it will round 145 up to 200 nevertheless.
Admin
I originally tried to use a simple formula with log, but it wasn't always accurate due to rounding. The following Java code runs about 10 times faster than the original (when translated into Java):
Admin
Admin
If I'm not mistaken, it will work for 'any' length number. It's only checking the first three digits because that's how rounding works (usually you only look at the first two but anyway.)
Admin
Fred Flintstone, what was the rounding problem? Would the following not work?
private int calculateGap(int min, int max, int interval)
{
int gap = (max - min) / interval;
int digits = (int)(Math.log(gap) / Math.log(10));
double roundingFactor = Math.pow(10, digits);
return (int)(Math.round(gap / roundingFactor) * roundingFactor);
}
Admin
PointF[] ChartData(string funct, int xmin, int xmax, int npts) {
PointF[] pts = new PointF[npts];
float step = (xmax-xmin)/(float)(npts-1);
for(int j = 0; j < npts; j++) {
pts[j].X = (float)(xmin + step*j);
pts[j].Y = (float)(Expression.expression.Evalute(funct, new string[]{"x"}, new double[]{pts[j].X}));
}
return pts;
}
Admin
Actually, it's even more absurd than most of the respondents realize. Why? Because a close look at the code shows that it is in C#, and (as one of the anonymous poster showed) the standard C#.Net Math.Round() method takes a precision argument.
Admin
I see three optimizations here:
1. The function takes min, max, and interval arguments. This saves on one of those expensive floating point subtraction operations.
2. Hand coded loop unrolling in assigning the digit variables. Sometimes "for" loops are just too slow.
3. The variable "result" is declared near the top of the function and initialized to zero. Then, at the bottom, it is assigned a value, and immediately returned. Because if he had returned the expression "firstDigit * (int)Math.Pow(10, length - 1)" directly, it would take up a lot more space on the stack.
You're all just jealous because this guy is a l33t h4X0r and you're not.
Admin
You sure?
It doesnt reevaluate secondnumber, so secondnumber will still be 4 so it will not be >=5.
Rounds 145 to 155 (which is odd in itself mind).
Admin
That would not do the same thing as the WTF code, so without the spec we have no way of knowing whether it would be a better or worse solution. If the spec says that numbers between 145 and 150 should be rounded up to 200, then Math.Round() would not be adequate. Stick to removing the WTF-ness of the actual code rather than solving a different, slightly simpler problem.
I'm not saying that the WTF code can't be simplified, but that doesn't mean we should jump to using the simplest thing we can think of whether or not it actually does what it's supposed to. We don't know exactly how the code was supposed to behave, and we could guess that the x45 thing was a bug, but it might actually be a requirement, and the very reason the programmer chose to implement it this way instead of using Math.Round()
Admin
Now, you're wrong too. In the end, 145 will be round up to 200 because he first evaluates the third digit, then the second one.
Start with 145.
firstDigit -> 1
secondDigit -> 4
thirdDigit -> 5
Since thirdDigit >= 5, secondDigit -> SecondDigit + 1 -> secondDigit -> 5
Then secondDigit >= 5, firstDigit -> firstDigit + 1 -> firstDigit -> 5
Finally, result -> firstDigit x 100 -> 200.
However, keep in mind that 14567890 will also be rounded to 20000000 because it starts with 145.
One fun thing though... What would happen if Max < Min? [:D] Or worse, when Max equals Min? [:D] Okay, we all know whe should not return 0 as Interval but what if we give a negative Interval?
Admin
You might scream WTF at this solution but it's guaranteed to work in Microsoft Visual Studio C++:
Laziest solution to rounding a number:
double dSomeNumber = 1.2345;
CString strTemp;
//Rounding to two significant digits
strTemp.Format("%.1e", dSomeNumber);
dSomeNumber = atof(strTemp);
Change the number between . and e to change the digits of precision.
Bingo.
My lengthier post above this one uses a similar technique that creates an object (containing an array of numbers) that mimics Excel's way of auto-formatting the labels on an axis. I will give the full .h and .cpp if somebody replies.
Admin
Morover, the reason why the long code I posted is longer than everybody else's is because it takes into consideration many error situations:
One way to improve my code would be to add an extra argument for a target number of intervals. Right now it assumes that mere mortals can only handle between 5 and 10 intervals, and chooses the best number of intervals to fit the data.
Admin
In response to Schoool-Re-Lea's post, the code is written in Java, not C#. I guess that won't matter though.
Admin
The original code would round 145 up to 200 (1450->2000, 14500->20000, etc.). This solution does not.
Admin
In theory, this should work:
The problem is that when it should get a value of 2, it gets 1.999999999. You can fudge it by adding 0.5500000001, but that's kinda ugly. Besides, the pow and log functions are quite a bit slower. Ignoring the fact that your original algorithm didn't handle values like 145 correctly, it is still about 10 times slower than the iterative solution I posted. The above is about 1.5 times slower than your solution, but does handle 145 correctly.
Admin
At my last job our client was actually requesting this mode of rounding. We were still trying to talk them out of it when I left.
In any event, it's still not neccesary to convert to Stings to acomplish this. You can do it in a number of ways, including (but not limited to) doing two half up rounds. If I were to rewrite this (and wasn't concernd with floating point errors) and was pretty sure it was a one time need, I'd probably do something like:
double temp = rawGap;
while (temp >= 100) temp = temp / 10;
temp = Math.round(temp);
temp = temp / 10;
temp = Math.round(temp);
Which isn't neccesarily more performant than the original, but it's a lot easier to understand IMO.
Admin
Here's the ful solution of the above. I think it works, but only if raw gap >= 1 , of course. The original solution would also fail for numbers smaller than 1, I believe.
double temp = rawGap;
int size = 0;
while (temp >= 100) {
i++;
temp = temp / 10;
}
temp = Math.round(temp);
if (temp >= 10) {
i++;
temp = temp / 10;
}
temp = Math.round(temp);
return temp * Math.pow(10, i);
Admin
If it is, then the coder must have been studying C# at the time he/she wrote it and got confused, because there are at least three things I can see here that would be wrong if it were Java code:
Admin
So, that routine will round up 045 to 100!
thats rubbish!
Admin
Rubbish? Yep, but it is the functionality that the original programmer wanted to have, apparantly, with his WTF code. Yes, it seems crazy and perhaps it is even crazy but it wouldn't suprise me that this has even been part of the original design! [:)]
Admin
Try floor( x + 0.5 ), if there's no round() function.
Forgive me, but I didn't look at the code to see if you needed nearest-even behavior, or some other atypical rounding.
Admin
public String getPaula(int toRound) { String paula = "brillant";
}
Admin
Assuming that gap cannot be negative, this function is equivalent:
I am not actually sure what the original code would do for a negative gap. I assume that it would crash on the hyphen character here:
firstDigit = int.Parse(gapString.Substring(0, 1));