Trillian
Trillian

Reputation: 411

How to easily output x to the power of n as a string

I need to output large numbers like for example 847288609443 as 3⁴⁵. All of my numbers have the form 3^n or 3^n -1. I use the hints from this post. For now my code looks like :

public static void main(String[] args) throws IOException {        
   Map<String,Character> map = new HashMap<>();
   map.put("-", '\u207b');       map.put("5", '\u2075');
   map.put("0", '\u2070');       map.put("6", '\u2076');
   map.put("1", '\u00b9');       map.put("7", '\u2077');
   map.put("2", '\u00b2');       map.put("8", '\u2078');
   map.put("3", '\u00b3');       map.put("9", '\u2079');
   map.put("4", '\u2074');       

   for(int i = 1; i< 50; i++){          
       String [] s = String.valueOf(i).split("");
       StringBuilder sb = new StringBuilder();
       sb.append("3");
       Stream.of(s).forEach(e->sb.append(map.get(e)));
       System.out.println(sb.toString());
   }
}

unicode values are from this wiki page:(https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts)

Is there another way of doing such a conversion instead of spliting the string value of my exponents and appending unicode chars?

Upvotes: 1

Views: 186

Answers (3)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726779

You can implement this as a mapping of codepoints. Here is an implementation for non-negative numbers:

private static final int[] superCodepoint = new int[] {
'\u2070', '\u00b9', '\u00b2', '\u00b3', '\u2074', '\u2075', '\u2076', '\u2077', '\u2078', '\u2079'
};
public static String ToSuperscript(String s) {
    return s.codePoints()
        .map(c -> Character.isDigit(c) ? superCodepoint[Character.digit(c, 10)] : c)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

Demo.

Upvotes: 1

Matt Timmermans
Matt Timmermans

Reputation: 59233

I'm going to assume that your code does what you want...

The idea of converting each digit to a unicode superscript and appending to a StringBuilder is fine, but your implementation is not very efficient -- especially in the split. If that's bothering you, then you can do it like this, which will be a lot faster:

static final String SUPDIGITS = "\u2070\u00b9\u00b2\u00b3\u2074\u2075\u2076\u2077\u2078\u2079";

public static void main(String[] args) throws IOException {        

   StringBuilder sb = new StringBuilder();
   for(int i = 1; i< 50; i++) {
       sb.setLength(0);

       //append digits in reverse order
       int v = i;
       for (;v>0;v/=10) {
           sb.append(SUPDIGITS.charAt(v%10));
       }
       //and then the 3
       sb.append("3");
       //and then reverse it
       sb.reverse();
       System.out.append(sb).println();
   }
}

The major difference here is that this version does many fewer memory allocations.

Upvotes: 2

Maurice Perry
Maurice Perry

Reputation: 9650

You could do something like that:

private static char[] DIGITS = {
        '\u2070', '\u00b9', '\u00b2', '\u00b3', '\u2074',
        '\u2075', '\u2076', '\u2077', '\u2078', '\u2079'};

public static String toSuperscript(int i) {
    boolean neg = i < 0;
    if (neg) {
        i = -i;
    }
    char[] chars = new char[15];
    int k = chars.length;
    do {
        chars[--k] = DIGITS[i%10];
        i /= 10;
    } while (i > 0);
    if (neg) {
        chars[--k] = '\u207b'; // minus sign
    }
    return new String(chars, k, chars.length-k);
}

public static void main(String[] args) throws IOException {        
   for(int i = 1; i< 50; i++){          
       System.out.println("3" + toSuperscript(i));
   }
}

Upvotes: 2

Related Questions