Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

For my project, I need to convert dollar to cents, so I wrote the following function to safely do the conversion. The input dollar is float and the output should be int.

def safe_dollar_to_cent(dollar):
    parts = str(dollar).split('.')

    msg = 'success'
    status = 0
    if len(parts) == 1:
        return status, int(parts[0])*100, msg

    decimal_part = parts[1]
    if len(decimal_part) > 2:
        decimal_part = decimal_part[0:2]
        msg = 'dollar has been truncated: {} -> {}'.\
              format(parts[1], decimal_part)
        status = 1

    ret = int(parts[0]) * 100
    multiplier = 10
    for i, s in enumerate(decimal_part):
        ret += int(s) * multiplier
        multiplier /= 10

    return status, ret, msg

I am posting here for seeking other some pythonic way of doing this job.

Update:

my input is expected to be float, the return value should be int. The reason of this implementation is that I found the following incorrect computation.

18.90 * 100 = 1889.9999999999998

share|improve this question
    
What are you expecting dollar to be, a number or a string? – SuperBiasedMan Feb 25 at 11:56
6  
Just to understand what seems overly complicated, what was wrong with return int(dollar * 100)? – Mathias Ettinger Feb 25 at 11:58
4  
You aren't using fixed-point dollar values? Shame on whoever provided you that interface, floating-point math is anathema for financial stuff. docs.python.org/2/library/decimal.html – JAB Feb 25 at 15:47
    
If you are in total control of your project, consider using cents instead of dollars. Otherwise, consider using Decimal numbers and you w ill have no issue by directly doing int(d * 100.), ((d * 100.) - int(d * 100.)) / 100. to return a pair having the result and the data you lost – Luis Masuelli Feb 25 at 17:53
    
About your update: you should not use floating point to store money values: what you type as 18.90 is really stored as a binary fractional number, with a little error. But anyway if you use doubles (8 bytes, precision 52 bits), all you need is rounding after the multiply. The error will disappear – edc65 Feb 25 at 20:25

I don't like the 3 argument return you're doing. You're using status and msg to actually do the same thing. They both return a signal of success unless the dollar is truncated. You don't need both pieces of information. Personally, I'd just say that you only need to print a note about the dollar being truncated so that the function only returns the cents value.

Now, you're also overlooking a very simple formula to convert this:

cents = dollars * 100

You don't need anything more complicated than that for the basic function:

def safe_dollar_to_cent(dollar):
    cents = dollar * 100
    return cents

If you're not sure that dollar will be a number, you can try converting it:

def safe_dollar_to_cent(dollar):
    cents = float(dollar) * 100
    return cents

As for truncating, I think it's better as an option. Let the user choose whether or not something will be truncated:

def safe_dollar_to_cent(dollar, truncate=True):
    cents = float(dollar) * 100
    if truncate:
        return int(cents)
    else:
        return cents

int will turn cents into a whole number instead of a decimal, so it's effectively truncating everything after the ..

share|improve this answer
1  
I think the statements in the if truncate are swapped. Also, instead of printing a note, maybe use warnings.warn? – Sjoerd Job Postmus Feb 25 at 15:15
    
@SjoerdJobPostmus You are correct! Thanks for catching that. You could post a separate answer about warnings.warn. – SuperBiasedMan Feb 25 at 15:40
2  
18.90 * 100 = 1889.9999999999998 in my python 2.7.5. – Alex Feb 25 at 17:49

First of all, good job on the solution. It works nicely. Contrary to the other answer here, returning boolean success and message is a industry convention.

What I would suggest is to split the validation and conversion into two functions like this:

def validate_dollar(dollar):
    return dollar * 100 % 1 == 0

def safe_dollar_to_cent(dollar):
    if validate_dollar(dollar):
        return {'success': True, 'cents': int(dollar*100)}
    else:
        return {'success': False, 'msg': 'Malformed input'}

print(safe_dollar_to_cent(10.9))
print(safe_dollar_to_cent(10))
print(safe_dollar_to_cent(10.90))
print(safe_dollar_to_cent(10.999))
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.