Until Sun adds log-base-10, what do you do?

Sadly, in java, due to inaccuracies of double divisions, log10(1000) == 2. This is a bit of a bummer - basic algorithms completely fail when you can’t even get log( 1000 ) to equal 3 :(.

(NB: it actually comes out as 2.999999999999999996 - which, obviously, is wrong, however you look at it)

In the past, I’ve written entire classes to get around Java’s crapness in this regards (yes, I know they have finally added log10 to java 5, thank god, but I still use 1.4 for everything), and it looks like I’m about to have to do so again, using hand-tweakable epsilons to enforce things like 2.999… == 3.

But, surely there’s a better way? What do you use?

As a schooled ‘FORTRANER’ (Faculty of Science), I will use hand-tweakable epsilons too. Maybe there is not more elegant method.
And I must say that I am shocked to hear that log10(1000) == 2 in java 1.4. I wasn’t aware of that!

I’m just curious, what are you coding such that you need to be using logarithms in the first place? And why is 2.9999… not good enough?

Its right to about 19 places which isnt bad.

And I fai lto see how that is 2 for anyting but very stupid truncation. Mayvbe Im missing something but if your trucnating that to 2 rather then rounding to 3 I dont think you can blame Java…

I don’t think it’s that bad, just round it. Blame “Floating Point” math if you like. I am pretty sure you will get the same result in any C/C++ libraries too.

The integer result of a log is - in every place I have ever seen it used in my life - the largest integer less than or equal to the actual non-integer result. i.e. always-round-down. i.e. java’s own built-in int-conversion.

So, no - incorrect at 19 dec plac isn’t “bad” - it’s just completely wrong.

The rest of your post seems to be missing the point. Especially considering what you call “very stupid” is in fact java’s very handy built-in behaviour. The problem with java is that log(A)/log(B) is extremely inaccurate for common real-life values of A and B, whereas a standard-library method of logB(A) for the world’s most common values of B (2 and 10) would largely avoid these inaccuracies, and would more often get a correct answer, I believe.

Hmm. I thought people would understand what I meant by integer logs. Sorry, guys.

Here you go (hopefully this is self-evident why the above suggestion won’t work without epsilons):

floating point: log-10( 999 ) == 2.999…
floating point: log-10( 1000 ) == 3

But, in java, they both equal 2.999(something)

int: log-10( 999 ) == 2
int: log-10( 1000 ) == 3

See?

I think what you need is the BigDecimal class:


    BigDecimal bd  = BigDecimal.valueOf( Math.log10(999d) );
    int intlog = bd.setScale(0, BigDecimal.ROUND_UP).intValue();

    System.out.println( intlog );

    bd  = BigDecimal.valueOf( Math.log10(1000d) );
    intlog = bd.setScale(0, BigDecimal.ROUND_UP).intValue();

    System.out.println( intlog );


Output is:
3
3

[edit] Use BigDecimal.ROUND_CEILING if you are rounding signed values towards positive infinity - will also work here in place of ROUND_UP [/edit]

[EDIT-EDIT] Just noticed you don’t want to use JRE 1.5 for the Math.log10 call, that’s ok though the BigDecimal round for 1.4 should still be better then an epsilon [/EDIT-EDIT]

I don’t get it. Floating point operations are only as accurate as the size of the floating point type and the computation in question, so 2.99999… is as good as it gets. Requiring the truncated (cast to int) value of a floating point value to behave like you describe would ruin the precision of any other (normal) floating point computation. What exactly is wrong with Math.round()? Sure a “direct” log10(x) for x = 1000 gives you a truncated 3 for this case, but you can’t count on that for all values of x (esp. large ones). If you need the integer value, rounding is just as good.

  • elias

Ditto on I don’t get it.

It sounds to me like you are trying to get integer results out of a float operation.

So what youa re really complainign abotu is that there is no integer log function.

For the record, I don’t remember other log functions being integer, in fact I seem to remember my log tablkes being full of decimal places.

Maybe I still don’t understand you.

depence on what you do with the rest of the equations

somethimes Approximations don’t cut it. With the created errors can have annoying result. also mind that significance decreases fast wen doing multiplications.

I assume you mean that you are actually doing Log(1000) / Log(10) which isn’t exactly 3.

Instead of epsilons, how about writing your own log10 function that checks for input values of 10, 100, 1000… and returns integers, but otherwise returns Log(A) / Log(10).

EDIT:
The only reason I can think of for needing the integer part of a logarithm is to calculate the number of digits in a decimal representation. log10(i) is String.valueOf(i).length() - 1. So, what do you need it for?