1

I am trying to write a program that asks the user for a decimal number and then calculates the sum of its digits. for example if the number is 123.25 then the sum will be 1+2+3+2+5=13.

I decided to first turn the number to 0.12325 (any number will be formatted this way but I am using the example) and then move the decimal point to the right one place and isolate the digits one by one.

here is what I got (I tried it in python and c++ i get the same problem in both):

number = float(raw_input ("please enter a Decimal number: "))
total = 0

while number >= 1:
    number = number / 10 ## turning 123.25 to 0.12325

while number > 0:
    number = number * 10 ## making 0.12325 to 1.2325
    total = total + int(number)  ## storing the digit on the left of the decimal point
    number = number  - int (number) ## getting rid of the digit left to the decimal point

print total

The problem is that everything works fine until the last digit. When it comes to the point where it's 5.0 than the statement number = number - int(number) gives me 1 instead of zero. It is supposed to be 5.0 - 5 = 0 but it isn't.

This is what I get when i print the number at every stage:

please enter a Decimal number: 123.25
0.12325
0.2325
0.325
0.25
0.5    ##### Here is where the problem starts #####
0.999999999999
0.999999999993
0.999999999929
..... here it goes on for  a while. I spared you the rest .....

More accurately, I printed the number at every step in the loop:

please enter a Decimal number: 123.25

number at start of loop:  0.12325
number after 'number * 10' :  1.2325
number at the end of the loop:  0.2325

number at start of loop:  0.2325
number after 'number * 10' :  2.325
number at the end of the loop:  0.325

number at start of loop:  0.325
number after 'number * 10' :  3.25
number at the end of the loop:  0.25

number at start of loop:  0.25
number after 'number * 10' :  2.5
number at the end of the loop:  0.5

number at start of loop:  0.5
number after 'number * 10' :  5.0
number at the end of the loop:  0.999999999999

All of a sudden it stops being accurate.

user170800
  • 13
  • 1
  • 3
  • sorry, when I wrote the question the formatting wasn't messed up like that – user170800 Mar 10 '15 at 18:27
  • What type are you storing the number in? –  Mar 10 '15 at 18:27
  • I am storing the number as a float – user170800 Mar 10 '15 at 18:28
  • And that is your problem. You may wish to read https://docs.python.org/2/library/decimal.html –  Mar 10 '15 at 18:29
  • How can i fix it then? – user170800 Mar 10 '15 at 18:31
  • @bigstones while code block formatting does work for that edit, it also enables syntax highlighting (which is incorrect on output) and doesn't help with the readability. –  Mar 10 '15 at 18:31
  • I'd start by reading the document on the decimal type. –  Mar 10 '15 at 18:31
  • (I'm not a python person, nor do I have python at my disposal here to explain it - I'm a Java / Perl guy and I looked for "big decimal python" to find that. Its kin in Java is [BigDecimal](http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) and perl is [Math::BigFloat](http://perldoc.perl.org/Math/BigFloat.html) - once you know what to look for, its easy to find the corresponding class in another language) –  Mar 10 '15 at 18:35
  • Wouldn't this question be more appropriate on Stack Overflow? – 5gon12eder Mar 10 '15 at 19:04
  • 3
    Just output the number to a string and go through it char by char. – whatsisname Mar 10 '15 at 19:37
  • whatisname I wanted to avoid that actually but that would be simpler, I agree. – user170800 Mar 10 '15 at 19:39
  • getting the result is less important to me, I just wanted to know why the problem occurs. – user170800 Mar 10 '15 at 19:40
  • 1
    @user170800 you may wish to delve into the [tag:floating-point] tag and see other similar questions. I've got an answer elsewhere that my help you: [When do rounding problems become a real problem? Is the least significant digit being one off really a big deal?](http://programmers.stackexchange.com/a/224865/40980) (and can work on explaining what is going on at the bit level later). –  Mar 10 '15 at 20:01
  • So if I got it right after reading a bit about it. When I do "5.0 - 5" it doesn't really become zero due to precision problems so instead it might store 0.0000000000009328482 or something like that, which is the reason why my "while number > 0" statement is still running even though I expected it to hit zero and stop. – user170800 Mar 10 '15 at 20:17
  • Thank you guys for the help. it is much appreciated. thank you MichaelT for pointing me in the right direction. and also Whatsisname and Steven Burnap for suggesting an alternative that worked. thanks guys :)) – user170800 Mar 10 '15 at 20:19

1 Answers1

2

This can be done with the following python one-liner:

>>> f = 123.25
>>> sum(int(ch) for ch in str(f) if ch.isdigit())
13
>>>

To break down how this works:

Convert to string as @whatsisname recommends to avoid floating point rounding issues

str(f)

Create a list containing each character

ch for ch in str(f)

Throw out everything that isn't a digit

ch for ch in str(f) if isdigit(ch)

Convert everything in the result to an int

int(ch) for ch in str(f) if isdigit(ch)

Sum everything

sum(int(ch) for ch in str(f) if isdigit(ch))

There are three key points here:

  1. Do not be afraid to convert numbers to strings. The performance hit of doing so is usually inconsequential on modern machines, and this makes manipulating digits much more natural
  2. Python list comprehensions combined with standard functions are extremely useful for anything that involves "do something with this list of something".
  3. When using floating point math, you should never expect exact results except in trivial cases (like 0.0) because of precision issues.
Gort the Robot
  • 14,733
  • 4
  • 51
  • 60