What's more sturdy, a string or a log?
Submitted by Blake on Fri, 03/12/2010 - 12:57My co-worker Derek asked me a simple question: How would I round a number down to two significant digits? That is, how would I convert:
125 -> 120 3452 -> 3400 89354 -> 89000
Derek is working with a third-party graphing tool. He needs this value to scale each graph relative to the size of his coordinates. I'm not on his project but I was intrigued enough to bang out some quick code - not pseudo-code, but fully-functional.
Note: There is one exception. He wants 34 to be converted to 30, even though 34 itself has two significant digits. Scope creep, we'll have to add special logic.
Additional rule: 34 -> 30
It raises an interesting question: How does a program know how many digits a number has? How can it tell just HOW big a number is?
Well, humans can just look and see how big it is. And a program can do that too.... through string manipulation. This was Derek's first instinct. Convert the int to a string, loop through the characters, build a new string with either the original characters or with "0".
private int RoundSecondLargestDigit_String(int num)
{
if (num < 10) return 0;
string s = num.ToString();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
sb.Append((i < 2 && i < s.Length - 1) ? s.Substring(i, 1) : "0");
}
return Int32.Parse(sb.ToString());
}Me, I'm not a huge fan of using strings for a math job. I knew it could be approached mathematically, and most likely, I'd have to dust of some logarithm skills. Some basics:
10^3= 1000 log10(1000)= 3 log10(1001)= 3.0004 log10(9999)= 3.99995 log10(10000)= 4 So basically: NumberOfDigits(x)= floor(log10(x)) + 1
From there, it's pretty easy to figure out the number of zeroes we need (Number of digits - 2, except the "34" special case). For 8934, the number of zeroes is 2. 8934 mod 10^2 = 34. 8934-34= 8900.
And in code form:
private int RoundSecondLargestDigit_Log(int num)
{
if (num < 10) return 0;
int zeroCount = Math.Max((int)Math.Floor(Math.Log10(num)) - 1, 1);
return num - (num % (int)Math.Pow(10, zeroCount));
}Definitely fewer lines, no looping, and no casting back and forth between int and string. If the "34" exception wasn't part of the deal, I wouldn't need that Math.Max(n,1) bit. In the string version, that " && i < s.Length - 1" bit was the "34" case handler.
I wrote some test code to print out the results.
protected void Page_Load(object sender, EventArgs e)
{
int[] tests = new int[] { 9, 10, 11, 34, 99, 100, 101, 131, 999, 1000, 1001, 1122, 12345 };
foreach (int test in tests)
{
PrintResult(test);
}
}
private void PrintResult(int num)
{
Response.Write(String.Format("{0}: String={1} Log:{2}
",
num.ToString(),
RoundSecondLargestDigit_String(num).ToString(),
RoundSecondLargestDigit_Log(num)));
}Sure enough, both of them work as expected.
9: String=0 Log:0 10: String=10 Log:10 11: String=10 Log:10 34: String=30 Log:30 99: String=90 Log:90 100: String=100 Log:100 101: String=100 Log:100 131: String=130 Log:130 999: String=990 Log:990 1000: String=1000 Log:1000 1001: String=1000 Log:1000 1122: String=1100 Log:1100 12345: String=12000 Log:12000
So now the question becomes: which version do you use? Would Derek say tomAYto or tomAHto? Not taking performance into account for a second, it's two equivalent paths leading to the same place - one with strings, one with math.
But are they equivalent? Stanislas Dehaene asks that question another way: Log or linear?
"The mapping of numbers onto space is fundamental to measurement and to mathematics. Is this mapping a cultural invention, or a universal intuition shared by all humans regardless of culture and education? We probed number-space mappings in the Mundurucu, an Amazonian indigene group with a reduced numerical lexicon and little or no formal education. At all ages the Mundurucu mapped symbolic and non-symbolic numbers onto a logarithmic scale, while Western adults used a linear mapping with small or symbolic numbers, and a logarithmic mapping when numbers were presented nonsymbolically under conditions that discouraged counting. Thus, the mapping of numbers onto space is a universal intuition, and this initial intuition of number is logarithmic. The concept of a linear number line appears to be a cultural invention that fails to develop in the absence of formal education."
To babies and this Amazonian group, logarithmic counting is the natural way to count. 1-3-9-27 seems like a more logical sequence than 1-2-3-4. Mapping these numbers into a linear sequence is an imposition of the Western world. Sound a little like imposing strings in a math job?
How about you: What path would you take? How would you round a number down to two significant digits?
Next time, I take his fingers and I turn them into pretzels. I just might do the same thing to your face.
Submitted by Darius on Wed, 02/10/2010 - 21:26Well, call it an entry to be filed in the ever-expanding tome of Lessons Learned or just another case of Asking For It, but ITM HQ has been hacked relentlessly for the better part of the last two days. At first, a few fraudulent account openings, rapidly followed by intermittent, but consistent, postings of spammy comments of forum responses. I reconfigured the CAPTCHA settings as a means of slowing the attacks, at least until I got the latest Drupal update set up. Given that we were at 6.10 and should be updated to 6.15, I suppose all of the attacks were deserved, in a way. If idle hands are the devil's playground, a seldom updated Drupal site may be at least a breeding ground for the web's bad bacteria. And seeing as how we're enjoying more hits than ever, I could imagine the spammers preying on any site on the ascend. We're closing out year two of reaching Into The Mantle, and we've got a lot in store. Not the least of which is me uploading the past few podcast episodes. So, I better get back to that now, while the hour is nigh...
~dm
