11 Replies Latest reply: Apr 25, 2008 11:50 AM by 807591 RSS

    BigDecimal: merging integer part with fraction fastly and elegantly

    807591
      Hi all, I have two long values: long1 and long2 and I need to create a BigDecimal with value long1.long2 . Creating String object of these long values and using constructor BigDecimal(String) like
      long long1 = 15;
      long long2 = 82;          
      BigDecimal res = new BigDecimal(String.valueOf(long1)+"."+String.valueOf(long2));
      is too slow.
      Of course I can achieve the goal writing something like that:
                long long1 = 15;
      long long2 = 82;          
      BigDecimal right = new BigDecimal(long1);
      BigDecimal left = new BigDecimal(long2);
      int delta = 0;
      // count amount of digits
      while (true) {
      if (long1 == 0) 
      break;
      long1 = long1 / 10;
      delta++;
      }
      right = right.movePointLeft(delta);          
      BigDecimal result = left.add(right);
      But this decision is not an elegant one and perhaps there is a faster solution, isn't there?

      Thank you in advance

      Edited by: tell_me_the_truth on Apr 25, 2008 7:41 PM
        • 1. Re: BigDecimal: merging integer part with fraction fastly and elegantly
          800323
          Actually, using the String constructor of BigDecimal is the recommend way to create on (so that you do not have the IEEE floating point "problem").
          What makes you say it is too slow?
          • 2. Re: BigDecimal: merging integer part with fraction fastly and elegantly
            807591
            What makes you think that the first attempt was too slow? How many times
            are you performing that operation? Have you tested and proven that that's a bottleneck?
            Donald Knuth:
            "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
            • 3. Re: BigDecimal: merging integer part with fraction fastly and elegantly
              DrClap
              Sorry, once you decide the elegant solution is too slow (you do have empirical justification for that, right?) then in getting faster solutions you can't still demand elegance.

              I'm curious about a requirement that can never generate something like 15.035; is your data really structured like that?
              • 4. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                807591
                tell_me_the_truth wrote:
                Hi all, I have two long values: long1 and long2 and I need to create a BigDecimal with value long1.long2 . Creating String object of these long values and using constructor BigDecimal(String) like
                long long1 = 15;
                long long2 = 82;          
                BigDecimal res = new BigDecimal(String.valueOf(long1)+"."+String.valueOf(long2));
                is too slow.
                Can you explain how you came to that conclusion?
                Of course I can achieve the goal writing something like that:
                          long long1 = 15;
                long long2 = 82;          
                BigDecimal right = new BigDecimal(long1);
                BigDecimal left = new BigDecimal(long2);
                int delta = 0;
                // count amount of digits
                while (true) {
                if (long1 == 0) 
                break;
                long1 = long1 / 10;
                delta++;
                }
                right = right.movePointLeft(delta);          
                BigDecimal result = left.add(right);
                And how you figure this will be any faster than the String concatenation version?
                But this decision is not an elegant one and perhaps there is a faster solution, isn't there?
                Unless you have a valid reason to need to improve the speed of this operation (as in, you've profiled the app and this code is a bottleneck), then don't worry about speed, worry about readability and maintainability of your code.
                • 5. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                  807591
                  Thank you for your answers. I have tested the speed in nano seconds of the first solution(using constructor with String) an of the second one. the second solution was rather faster. Time is critical in my project - that's why I'm seeking for a better solution.
                  • 6. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                    807591
                    Code-level optimization is not effective before you've determined what the bottlenecks are. Profile the entire application and determine where you should be spending your optimization time. Trying to microoptimize every line of code will result in a project that is impossible to read or maintain. I'd also highly doubt you'd be able to deliver on time (or ever).
                    • 7. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                      807591
                      The problem is that this assignment(creating BigDecimal object of two longs) is performed a huge(really huge) amount of times and I must implement something which really "flyes". That's why I am investigating this point.
                      • 8. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                        DrClap
                        Nanoseconds?

                        I ran each of your two proposed versions in a loop one million times and timed the loops. The first (elegant) version took 1687 milliseconds and the second (allegedly fast) version took 2547 milliseconds.

                        Not looking good for micro-optimization yet. But wait... my code doesn't do anything with the BigDecimal objects, so maybe the runtime optimized those statements away. Could make a difference. So let's assign them to something which I print at the end: now elegant=1625 and fast=2500.

                        So, did anybody quote my brother Knuth about premature optimization yet? Oh yeah, there it is. Seconded.
                        • 9. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                          807591
                          It's hard to believe. I have tested it and got quite the opposite results. Could you show your testing application? Thanks
                          • 10. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                            DrClap
                            Here's part of it:
                            int loops = 1000000;
                            BigDecimal bd = null;
                            long start = System.currentTimeMillis();
                            for (int i=0; i<loops; i++) {
                              long long1 = 15;
                              long long2 = 82;          
                              bd = new BigDecimal(String.valueOf(long1)+"."+String.valueOf(long2));
                            }
                            System.out.println(System.currentTimeMillis() - start);
                            It should be obvious to you what the second part is.
                            • 11. Re: BigDecimal: merging integer part with fraction fastly and elegantly
                              807591
                                   public static void main(String[] args) {
                                        int loops = 1000000;
                                        BigDecimal bd = null;
                                        long start = System.currentTimeMillis();
                                        for (int i = 0; i < loops; i++) {
                                             long long1 = 15;
                                             long long2 = 82;
                                             bd = new BigDecimal(String.valueOf(long1) + "."
                                                       + String.valueOf(long2));
                                        }
                                        System.out.println("using first approach (BigDecimal(String)): " + (System.currentTimeMillis() - start));
                                        
                                        long start1 = System.currentTimeMillis();
                                        for (int i = 0; i < loops; i++) {
                                             long long1 = 15;
                                             long long2 = 82;          
                                             BigDecimal right = new BigDecimal(long1);
                                             BigDecimal left = new BigDecimal(long2);
                                             int delta = 0;
                                             while (true) {
                                                  if (long1 == 0) 
                                                       break;
                                                  long1 = long1 / 10;
                                                  delta++;
                                             }
                                             right = right.movePointLeft(delta);          
                                             BigDecimal bd1 = left.add(right);
                                        }
                                        System.out.println("using the second approach: " + (System.currentTimeMillis() - start1));
                                   }
                              The output is:

                              using first approach (BigDecimal(String)): 797
                              using the second approach: 344

                              I can't understand how you had got the opposite results.