Is there an alternative to the log
function that returns the correct result (3.0
) for (log 1000 10)
, currently it returns 2.9999999999999996
?
You can use fllogb
from math/flonum
library. Note that the arguments are in the different order.
@aymano.osman That’s just the nature of floating points. Do you need an exact result?
If you need an exact result you can use a cas instead. It computes symbolical so it will give an exact result, but will be slower.
#lang racket
(require racket-cas)
(normalize '(log 10 1000))
This will return 3.
Thank you so much @sorawee!
Why does fllogb
get it right, out of interest?
@soegaard2 Thanks, I’ll take a look at that.
Good question! Looking at the code: it first uses fllog
to compute the standard floating point logarithm. It then does a one Newton iteration. https://github.com/racket/math/blob/58f5d6205abeec854b47a6c70d613089f108bceb/math-lib/math/private/flonum/flonum-log.rkt#L138
Wow, that is interesting.
Just noticed that python behaves the same way, it just has a specific function for log base 10
>>> math.log10(1000)
3.0
>>> math.log(1000, 10)
2.9999999999999996
Do you need an exact result? - if not, I recommend using the standard log
. If the result is printed, you normally round it first and it will print as 3.0 anyway. If you need to compare it to something else - then use (<= (- a b) a-small-number-close-to-zero)
.
kotlin produces the same results println(log10(1000.0))
println(log(1000.0, 10.0))
So my understanding was wrong.
I was using the maths trick that log base 10 counts the number of digits (minus 1) in a number. (I was doing a silly code challenge online)
Floating points in various languages are usually represented as in the IEEE standard.
Back in the day you could buy a “math coprocessor” that could compute with these floating point numbers - and take logarithms etc. I think most cpus these days has floating point support.
Programming languages normally implement log simply by letting the cpu compute the result. This explains why you get the same result in multiple languages.
However there is a tension between speed and accuracy. Sometimes the floating point operations won’t return the most precise result.
I wonder if it would be appropriate for racket to also provide a specialised log10
like these other languages do?
(log 1000 10) computes log10.
Ah - now I get what you mean.
Say you want to use log
to “count number of digits” in a number.
Then you would use: (inexact->exact (floor (log x)))
You want numbers between 1000 and 9999 (inclusive) to all compute 3 – 3.99999999999
If you floor (log 1000 10)
you get 2, which is the problem :slightly_smiling_face:
Hmm.
(floor (log <1000-9999> 10)) == 3
<- this needs to hold
It’s a silly use-case, so no need to worry about it.
If you want the number of digits, (compose1 string-length number->string)
also works
I suppose that’s why fllogb
says:
It’s not silly at all.
@sorawee remember I’m doing a silly code-challenge where speed and memory usage is an issue :slightly_smiling_face:
Euler Project?
unless you do get a timeout/memory error from the contest, I’d say this is a premature optimization.
@soegaard2 leetcode
Looks like fllogb
is what you need for this problem.
@sorawee well I improved my rank a lot with this little trick, so I’m quite satisfied :slightly_smiling_face:
wait, so the rank depends on the running time too?
Why let a neat maths trick go to waste?
Yes, everything counts. Memory usage too.
Then why don’t you use C lol
The official Python docs says:
If you are serious about getting good ranking that is
Do you happen to know where one can find the implementation?
Racket is not known for speed. The program is reasonably efficient, but not super efficient
I have been implementing each challenge in multiple languages at the same time for fun. Each language is ranked separately.
It is mainly as prep for coding interviews too.
thank you both for your help
@aymano.osman Since log10(10^n–1)<log10(10^n) we can add a number smaller than the difference between them before flooring:
(define (len x) (inexact->exact (floor (+ (log x 10) 0.0000000000001))))
Should work even for very large numbers.
@aymano.osman I just took a look at leetcode, and the list of default languages is rather small - what was necessary to use Racket on that site?
FWIW in Julia log10(1000)
=> 3.0
I was using kotlin on the website and repeating the implementations in Haskell and Racket outside.
@okcohen has joined the channel