2

I'm learning c++ of my own, and I thought: "Where can I find some problems to solve?"... well, reading in stackoverflow I get interested in euler project, and here I am.

I'm doing the 4th problem (not asking for help BTW), but I have a very strange issue...

In this code, I want to separate a number in "digits"... that way I can say: if the first digit of the number is equal to the last, it is a palindrome number (number that can be read left to right or right to left an will be the same number... example: 90009).

All good, but the problem is when I try to divide an array element into a power... for example:

90009/power(10,4)=9 right? (using integers of course)... Well, code assigns the 9 to arregloDeNumero[4], and then

arregloDeNumero[4]*pow(10,4)= 89999 :O :O ?????????? it has to be 90000 right??

in addition, I put some cout<< code, if u want to run this function and see how it works in my mind :P

but my question is: is there some bad code wrote by me or is some kind of bug or lack of knowledge?

void verificarPalindromo(int x)
{

    int arregloDeNumero[6];
    int diferencia=0;

    for (int i=5;i>=0;i--){

        cout << "the number X is: " << x; 
        cout << "and the difference is: " << diferencia << endl;

        arregloDeNumero[i]= ((x-diferencia)/pow(10,i));

        cout << "array of i= " << i << "is: " << arregloDeNumero[i];
        cout << " and the difference is: " << diferencia << endl;

        diferencia+=(arregloDeNumero[i]*pow(10,i));

        cout << "the new difference is: " << diferencia << endl;

    }

}
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
  • 5
    Floating-point arithmetic is not exact. Truncating the number furthers that effect. – chris Aug 25 '14 at 00:32
  • but im using int no float at any part of the code :O – Gary Andres Gutierrez Fajardo Aug 25 '14 at 00:39
  • 4
    There's no `pow` function that returns integers. – chris Aug 25 '14 at 00:42
  • :O so i just have to assume that the calculations with pow can be wrong?? 9*10000 is 90000 not 89999... – Gary Andres Gutierrez Fajardo Aug 25 '14 at 00:45
  • The calculations are fine, but it's the same thing as trying to represent ⅓ in a finite number of digits. That's just how floating-point works. We were always taught to put the dot or line above repeating digits. The computer's representation doesn't allow for that and it's in base 2 instead of base 10, so different numbers repeat forever. – chris Aug 25 '14 at 00:46
  • i understand what you are saying, but 9*10000 is 90000, not 89999... how can i get the correct number after the operation? – Gary Andres Gutierrez Fajardo Aug 25 '14 at 00:50
  • While floating point arithmetic is generally inexact, in this case I don't see why these particular calculations have that problem. All the numbers involved are exactly representable. – T.C. Aug 25 '14 at 01:05
  • [Can't reproduce on coliru](http://coliru.stacked-crooked.com/a/f70d9b0ad83b78d6). What's your OS/compiler version? – T.C. Aug 25 '14 at 01:09
  • 2
    T.C. even if the numbers are exactly representable, it doesn't mean there aren't some small "epsilon" errors introduced during their production/calculation... it would seem that `pow(10,4)` is returning ~9999.99999999999 on the system in question. – Tony Delroy Aug 25 '14 at 01:12
  • @TonyD That would be a very buggy implementation of `pow` indeed. – T.C. Aug 25 '14 at 01:17
  • My compiler is codeblocks 13.12 T.C. Guys i understand what you are saying about the differences or deltas or something... but... HOW can i get the correct number? I dont wanna think that i just have to forget 'pow' – Gary Andres Gutierrez Fajardo Aug 25 '14 at 01:17
  • 1
    @T.C. not especially... it's meant to quickly produce results within an epsilon value or two of the true mathematical result - just seems especially bad when the inputs happen to be integers that are then naively truncated. Gary: you probably should forget `pow`... e.g. create an array with entries for 1,10,100,1000,10000 - however many you might need - then index into it. Alternatively, round your floating-point result *before* converting it to an integer (which truncates, removing the decimal component even if >= 0.5), or even write a function that does successive integer multiplications. – Tony Delroy Aug 25 '14 at 01:25
  • Related: http://stackoverflow.com/questions/16923249/unusual-output-from-pow – T.C. Aug 25 '14 at 01:45
  • @T.C. asserting an expectation for exactness doesn't make it so :-) While the implementation could ensure correct results for this and many other cases (but where to draw the line?), the special casing logic could be expected to slow down the evaluation of the general case. The C++ Standard just says of `pow`: `defined as exp(y*log(x))` - you must expect epsilon errors in `exp` and `log` as the values produced aren't likely to be exactly representable, and for the error in `log` to be exacerbated considerably by `exp`, though an implementation might not literally use `log` and `exp`. – Tony Delroy Aug 25 '14 at 02:00
  • Tony D thanks for the advice, i just use an array with 1,10,100,1000, etc... and int work, but... is it a good practice to solve this problem? – Gary Andres Gutierrez Fajardo Aug 25 '14 at 02:45
  • @TonyD Well, yes, it's technically a quality of implementation issue. A conforming implementation could also print an empty line as the required "diagnostic" when it encounters any error in the code and leave it at that, but I doubt anyone would claim that such an implementation is acceptable. – T.C. Aug 25 '14 at 03:05
  • @TonyD Also, I'm not sure which version of the C++ standard you are using, but all versions I checked defined non-complex `pow` by reference to the C standard (the C99 TC2 standard library), which in turn simply defines it as "compute x raised to the power y", with no reference to `log` or `exp`. – T.C. Aug 25 '14 at 03:17
  • @T.C. that implies there's been a lack of effort here, but it's more about runtime *priorities* - fast-as-possible operation in the general case vs. mathematically perfect behaviour when the parameters happen to be integral. FWIW, I do consider `pow`'s behaviour here acceptable, and while it's inevitable that surprised and frustrated users will keep bashing their heads against this periodically, at least the workarounds are simple to understand and implement, whereas speeding up `pow` for arbitrary floating-point values is clearly out of most dev.'s reach. – Tony Delroy Aug 25 '14 at 03:20
  • a simple lookup table is much faster than pow in this case since you don't need to deal with any multiplications or log/exp in the pow function – phuclv Aug 25 '14 at 03:29
  • @T.C. that's the definition. You don't know how it's implemented in reality. Since the exponent is a floating-point number, typically it must do that by log and exp, not by repeating multiplications – phuclv Aug 25 '14 at 03:32
  • @LưuVĩnhPhúc I was answering the claim that the C++ standard defines `pow` in terms of `log` and `exp`. It doesn't (for non-complex). – T.C. Aug 25 '14 at 03:43
  • @T.C. and you were right on that... I mistook the comment re complex as being generally applicable - sorry - but that's not to say that an implementation might not reasonably use the same approach for non-complex parameters. Anyway, for performance reasons I'd be disappointed if it didn't use an exponential machine opcode if available, and failing that `exp` and `log` if available, only falling back on a software implementation if unavoidable, and in anticipation of using hardware instructions I doubt the C Standard would put overly strict requirements re precision. – Tony Delroy Aug 25 '14 at 06:13

1 Answers1

1

Although your code does not contain any floating point, the pow() function returns double and there seems to be a problem in your understanding of floating point numbers. It is frequently the case that dividing floating point numbers can result in a value that is very slightly different (perhaps only one bit) from the exact result. When such a value is converted to integer it is truncated and results in the next lower integer.

You should either

a) use a strategy that is entirely implemented using integers, or b) use floating point, but ensure that conversions to int use rounding rather than truncation.

If you have a high enough warning level, the compiler should tell you about this potential problem.


Just to be clear, I would think the problem is here:

((x-diferencia)/pow(10,i))

The result of pow() for your integer arguments will be an integer value, but because the type is double the division is also double. It's floating point division that (usually) causes the problem of slight errors. It's possible the following change might fix it.

((x-diferencia)/(int)pow(10,i))
david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • so this happen in the convertion procces from float to int... And the problem is the loss of information... So is never sure to use 'pow' with int values? – Gary Andres Gutierrez Fajardo Aug 25 '14 at 02:43
  • No, you need pow() but you have to force it back to int and avoid floating point division. See edit. – david.pfx Aug 25 '14 at 03:17
  • 1
    i just test it in the code but it doesnt work... forcing integer value on pow gives the same error. Finally i use an array with 1,10,100,1000 etc... values, and that way it works perfectly... but, is this a good practice? – Gary Andres Gutierrez Fajardo Aug 25 '14 at 03:34
  • Yes, a power-of-tens table is often a good idea. You can fill it with a loop and pow()! You should still find out what's wrong with your code and get it to work. That's show you learn. – david.pfx Aug 25 '14 at 09:05