11

I'll use Java as an example here, as it may be completely language-specific, but I'm generally interested in ways to do this.
Of course, the simplest and obvious way is this:

Math.pow(10, x)

but as far as I know, power is a fairly expensive operation. Thus I thought that there should be a better way, because it seems so obvious - I just need x zeroes after the 1!

Edit: Yes, this may be premature optimisation. The context is a rounding operation to n decimal places, which often uses something like this:

private final static int[] powersOf10 = {1, 10, 100, 1000, 10000};
public static double round(double number, int decimals) {
    if(decimals < 5)
        return Math.rint(number / powersOf10[decimals]) * powersOf10[decimals];
    double c = Math.pow(10, decimals);
    return Math.rint(number * c) / c;
}

This is the current rounding function I use, as you can see I already use a lookup table for the most used values, but I'm still curious whether there's some bit-magic or the like to improve this.

xeruf
  • 2,602
  • 1
  • 25
  • 48
  • 11
    This sounds like an obvious case of premature optimisation. Do you have stats to show that a significant amount of time is spent on this line. – Philip Whitehouse Oct 27 '17 at 21:43
  • Its an interesting question to dive into to get a better understanding of binary math. Thing is, there propably isnt a faster way than provided by the Math library. So just for clarity sake, maybe explain your reason for this question? (E.i. if its an optimizing question, or purly out of curiousity?) – n247s Oct 27 '17 at 21:46
  • Actually...`Math.pow` will [delegate to `StrictMath.pow`](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/StrictMath.java#StrictMath.pow%28double%2Cdouble%29), which is a native operation (meaning that it's [written in C](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/StrictMath.c)). Why do you need it *faster*? What are you seeing in terms of performance that's causing you to think that this is slow? – Makoto Oct 27 '17 at 21:51

3 Answers3

37

The fastest way is

static final int[] POWERS_OF_10 = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
static int powerOfTen(int pow) {
  return POWERS_OF_10[pow];
}

...since no higher power of ten fits into an int. Sorry if you were expecting something cooler.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
7

This question is quite old, but for people landing here from a search, I hope this is useful.

I tested the performance of three approaches using JMH:

  1. Math.pow(10, exponent)
  2. Look up in an array, as per the accepted answer
  3. Look up in a hard-coded switch statement.

Here is the JMH benchmark code:

private static final long[] POWERS_OF_TEN = {
                       10L,
                      100L,
                    1_000L,
                   10_000L,
                  100_000L,
                1_000_000L,
               10_000_000L,
              100_000_000L,
            1_000_000_000L,
           10_000_000_000L,
          100_000_000_000L,
        1_000_000_000_000L,
       10_000_000_000_000L,
      100_000_000_000_000L,
    1_000_000_000_000_000L};

int exponent;

@Setup(Level.Iteration) public void randomExponent()
{
    exponent = RAND.nextInt(16);
}

@Benchmark public long mathPow()
{
    return (long) Math.pow(10, exponent);
}

@Benchmark public long arrayLookup()
{
    return POWERS_OF_TEN[exponent];
}

@Benchmark public long switchLookup()
{
    switch (exponent)
    {
        case 1:  { return                    10L; }
        case 2:  { return                   100L; }
        case 3:  { return                 1_000L; }
        case 4:  { return                10_000L; }
        case 5:  { return               100_000L; }
        case 6:  { return             1_000_000L; }
        case 7:  { return            10_000_000L; }
        case 8:  { return           100_000_000L; }
        case 9:  { return         1_000_000_000L; }
        case 10: { return        10_000_000_000L; }
        case 11: { return       100_000_000_000L; }
        case 12: { return     1_000_000_000_000L; }
        case 13: { return    10_000_000_000_000L; }
        case 14: { return   100_000_000_000_000L; }
        case 15: { return 1_000_000_000_000_000L; }
    }
    return 0L;
}

And (drumroll...) here are the results:

Benchmark                           Mode  Cnt    Score    Error   Units
PowerOfTenBenchmark.mathPow        thrpt   15   24.134 ± 32.132  ops/us
PowerOfTenBenchmark.arrayLookup    thrpt   15  515.684 ± 10.056  ops/us
PowerOfTenBenchmark.switchLookup   thrpt   15  461.318 ±  4.941  ops/us

So #2 array lookup is the fastest, confirming the accepted answer is correct.

If you think the POWERS_OF_TEN array literal initialiser is ugly (I agree), there is a shorter and possibly less error-prone way:

private static final long[] POWERS_OF_TEN = IntStream.range(0, 16)
    .mapToLong(i -> (long) Math.pow(10, i)).toArray();
Will Hains
  • 996
  • 1
  • 12
  • 21
0

Here is my solution:

double number = 7893.147895673;
int dp = 7;

String pattern = ".";
for (int i = 1; i <= dp; i++) {
    pattern += "#";
}//for (int i = 1; i <= dp; i++)

DecimalFormat df = new DecimalFormat (pattern);
System.out.println(df.format(number));

I'm quite pleased with this, I started learning Java three days ago, and I'm loving it!

sh.seo
  • 1,482
  • 13
  • 20
  • Seems nice, but afaik String parsing is a LOT slower than basically any mathematical operation ^^ – xeruf Aug 09 '21 at 11:38