10
\$\begingroup\$

Method:

  • Input: a string which represents an integer or a non-integer value.
  • Output: a string which represents the same value multiplied by 100.

Requirements:

  • No floating-point unless needed.
  • No leading 0s in the part left of the floating-point.
  • No trailing 0s in the part right of the floating-point.

I cannot use the Double.parseDouble method, because it sometimes yields an "ugly" result.

For example:

String.valueOf(Double.parseDouble("0.0071")*100)); // yields 0.7100000000000001
String.valueOf(Double.parseDouble("0.072" )*100)); // yields 7.199999999999999

Here is my code, and I would like to know if there are any cavities in it:

String MultiplyBy100(String number)
{
    StringBuilder sb = new StringBuilder();

    String[] parts = number.split("\\.");
    if (parts.length == 1)
        sb.append(parts[0]+"00");
    else if (parts[1].length() == 1)
        sb.append(parts[0]+parts[1]+"0");
    else if (parts[1].length() == 2)
        sb.append(parts[0]+parts[1]);
    else
        sb.append(parts[0]+parts[1].substring(0,2)+"."+parts[1].substring(2));

    if (sb.charAt(0) == '-')
    {
        while (sb.length() > 2 && sb.charAt(1) == '0' && sb.charAt(2) != '.')
            sb.deleteCharAt(1);
    }
    else
    {
        while (sb.length() > 1 && sb.charAt(0) == '0' && sb.charAt(1) != '.')
            sb.deleteCharAt(0);
    }

    return sb.toString();
}
\$\endgroup\$
2
  • \$\begingroup\$ @palacsint already answered this, but in a nutshell the issue is simply that floating point data types are imprecise and math operations on floats produce rounding errors at the edge of the precision of the data type (turning 0.0071 into 0.007100000000000001 for instance). That is totally fine as long as the error falls outside the precision you require. Decimal data types (scaled integers) on the other hand are not subject to those rounding errors. Math results from decimal types will be as precise as the inputs. Caveat: decimal operations are extremely slow compared to floats. \$\endgroup\$ Mar 21, 2014 at 12:23
  • \$\begingroup\$ Also, my comment that "Math results from decimal types will be as precise as the inputs" was on the simplistic side, but these comment fields are short. The results will be as precise as the least precise of the inputs, and still not always perfect mathematically, and quite slow because the operations are 100% software with no help from specialized hardware. The decimal data type is fundamentally the same thing whether you're dealing with Java, C#, C++, MySQL or SQL Server. This post is informative \$\endgroup\$ Mar 21, 2014 at 12:33

2 Answers 2

11
\$\begingroup\$
  1. It would be much easier with BigDecimals:

    String input = "00007.880000";
    BigDecimal hundred = BigDecimal.valueOf(100);
    BigDecimal result = new BigDecimal(input).multiply(hundred).stripTrailingZeros();
    
    System.out.println(result.toString()); // prints "788"
    

    It works with big numbers well:

    String input = "0000123456789123456789.123456789123456789123456789123456789880000";
    BigDecimal hundred = BigDecimal.valueOf(100);
    BigDecimal result = new BigDecimal(input).multiply(hundred).stripTrailingZeros();
    
    // prints "12345678912345678912.345678912345678912345678912345678988"
    System.out.println(result.toString()); 
    

    Two readings:

  2. The original code returns 788.0000 for 00007.880000 which I guess does not fulfill the specification.

  3. Java developers usually start method names with lowercase letters.

    Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

    Source: Code Conventions for the Java TM Programming Language, 9 - Naming Conventions

\$\endgroup\$
7
  • 1
    \$\begingroup\$ So much for the answer I was half way through \$\endgroup\$
    – rolfl
    Mar 20, 2014 at 12:29
  • \$\begingroup\$ What about 1.234? Will BigDecimal yield 123.4? \$\endgroup\$ Mar 20, 2014 at 12:31
  • 1
    \$\begingroup\$ @barakmanos you should read the documentation and try this. It will help you learn. But, yes, it will. \$\endgroup\$
    – rolfl
    Mar 20, 2014 at 12:32
  • \$\begingroup\$ Oh... was probably thinking of BigInteger... \$\endgroup\$ Mar 20, 2014 at 12:33
  • 1
    \$\begingroup\$ Thanks. Regarding your second comment: I assume that the input is already "aligned" with the requirements of the output, so 00007.880000 is not a viable input in my program (though, I should have probably mentioned that in the question). Regarding your third comment: I know, it's just a typo (happened when I copied the code I wanted to be reviewed into a separate method). Thanks again for the detailed answer. \$\endgroup\$ Mar 20, 2014 at 15:22
6
\$\begingroup\$

Aside from palacsint's great suggestions:

  • You are using a StringBuilder, yet you still are doing string concatenations.

  • Your code for removing the leading zeros duplicates the for while loop.

Also: Why is your original input a string? This doesn't feel right. I've got the feeling there is something wrong with the bigger picture of your code.

EDIT: I meant the while loops. Better would be something like:

int startAt = sb.charAt(0) == '-' ? 1 : 0;

while (sb.length() > startAt + 1 && sb.charAt(startAt) == '0' && sb.charAt(startAt + 1) != '.')
   sb.deleteCharAt(startAt);

EDIT 2: Better readable?

boolean negative = sb.charAt(0) == '-';
if (negative) sb.deleteCharAt(0);

while (sb.length() > 1 && sb.charAt(0) == '0' && sb.charAt(1) != '.')
  sb.deleteCharAt(0);

if (negative) sb.insert(0, '-');

(Add brackets to taste)

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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