I used this in VW for any arbitrary large integer , Works even if integer cannot convert to Float because > Float maxVal. (available at public store SYSEXT-floorLog)
Integer>>floorLog10 "Initial guess is based on digitLength and following approximation : (2 raisedTo: 10) > (10 raisedTo: 3)"
| i j step guess n | (self negative or: [self isZero]) ifTrue: [^self error: 'Can''t take log of number <= 0']. guess := (self digitLength - 1) * 8 * 3 // 10. i := self // (10 raisedTo: guess). step := 2. [step > 0] whileTrue: [n := 10 raisedTo: step. [j := i // n. j > 0] whileTrue: [guess := guess + step. i := j]. step := step // 2]. ^guess
Of course, for SmallInteger, Bert's solution might be faster.
As for Float, i guess a native log10 FFI call should behave better than self ln / 10 ln, since the latter implies 3 rounding operations (and an inexact operation). I did not check the former however.
Nicolas
Bert Freudenberg a écrit :
Well,
(self asFloat + 0.9) log truncated + 1
would work reliably for SmallIntegers.
The nested conditionals might still win ... in particular if it was not binary search but based on frequency of numbers.
- Bert -
On May 30, 2007, at 15:02 , Alexander Lazarevic' wrote:
Hi Göran,
when I wrote printStringBase: I remember I tried to use x ln / base ln to get the string length with the same results as you are. Depending on floats it is just not robust. I went with Stream to keep it simple. It sure can help to have an optimized version for the major base rather then using printStringBase: 10.
Alex
Göran Krampe schrieb:
Hi!
In playing around with SmallInteger>>printString (see bugs.squeak.org/view.php?id=6512) I tested this code for calculating the length of the String:
self log truncated + 1
...but that doesn't work. The current code in my ChangeSet uses an unrolled binary search (nested ifs) which is 7x faster (#decimalDigitLength) so the above code is not something we would like to use, but I still wonder why it fails and what I would have needed to do about it to get it to work:
999 log truncated ===> 2 As expected.
1000 log ===> 3.0 As expected.
1000 log truncated ===> 2 Eh, what? Not expected!
...ok, yes, I know - Floats are the "tar pits of hell" when it comes to expected results - but... can someone answer if this is a bug or if I simply can't expect this code to work?
regards, Göran
PS. Strongtalk does in fact do SmallInteger>>printString almost exactly like my enhancement does (didn't peek, promise!) but does it around 5x faster than Squeak. :) I fired it up to look at how it does #log but log wasn't implemented. On the other hand Bryce tested Exupery on my code and it made a real difference - at least 2x better (not sure if he only tested printString). And then he mentioned an obvious improvement in Exupery that would make it even faster. Interesting method for comparing!