0

I want to convert a source base number to a destination base number, but I have a problem with fractions. When I trying to convert 10.234 (base10) to base 7 = 13.14315 it works perfectly, or aaaaa.0 (base16) to base 24 = 22df2 it also works.

But when I try to convert aaaaa.cdefb0 (base16) to base 24 = 22df2.j78da it doesn't work. I can't calculate fraction part and I get 22df2 as the answer

my code for base conversion :

private static String baseConversion(String number,
                                         int sBase, int dBase) {
        return Long.toString(
                Long.parseLong(number, sBase),
                dBase);
    }

my code for fraction conversion :

private static String fractionConversion(double fraction, int dBase) {
        StringBuilder output = new StringBuilder(".");

        for (int i = 0; i < PRECISION; i++) {
            fraction *= dBase;
            output.append(Long.parseLong(Integer.toString((int) fraction)));
            fraction -= Long.parseLong(Integer.toString((int) fraction));
        }

        return output.toString();
    }
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
androboy
  • 356
  • 1
  • 2
  • 9

2 Answers2

1

In your code below you should be appending a symbol for the base, not a number. Use the number to index into an array of symbols for the base.

And I recommend using integers for your remainder and product computations as you will eventually lose precision using floating point values.

        for (int i = 0; i < PRECISION; i++) {
            fraction *= dBase;

            // what are you appending here?  It should be a symbol
            output.append(Long.parseLong(Integer.toString((int) fraction)));

            fraction -= Long.parseLong(Integer.toString((int) fraction));
        }

Here's a more complete example.

  static String symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

   // assumes a string in the form of .293093
   // number of places
   // destination radix.
   public static String expand(String decimalFraction, int places, int dr) {

      decimalFraction = decimalFraction.substring(1); // ignore decimal point
      int numerator = Integer.parseInt(decimalFraction);
      int denominator = (int) Math.pow(10, decimalFraction.length());
      StringBuilder sb = new StringBuilder(".");
      for (int i = 0; i < places; i++) {
         numerator *= dr;
         sb.append(symbols.charAt((int) (numerator / denominator)));
         numerator %= denominator;
         if (numerator == 0) {
            break;
         }
      }
      return sb.toString();
   }
WJS
  • 36,363
  • 4
  • 24
  • 39
  • Sorry but I still couldn't figure it out, it may be obvious for you but how can I convert af.xy(base 35) to 17 then? I tried to put "int numerator = Integer.parseInt(decimalFraction, 35);" but it gives IndexOutOfBoundsException – androboy Aug 14 '19 at 20:32
1

I earnestly cannot recommend doing this, but I'll answer the question anyhow.

I would simply split the two numbers and treat them separately. First and foremost, how fractions work outside of Base 10 is not a 1-for-1 conversion of the trailing number. .25 in base 10 is not .11001 in binary, it's .01.

Every decimal place in your number represents a new magnitude; in base 10 it's values of 10^-1, 10^-2, and so on. When you change bases, you still change magnitudes but at different rates: 2^-1, etc.

.25 is thus analogous to 2/10 + 5/100 in base 10, and 0/2 + 1/4 in base 2. This leads to a new problem, where if the divisor of a fraction isn't a power of your new base, you usually get an irrational number. 1/20 is .05 in decimal, but in base 2 it's:

0.00 0011 0011 0011 //endless

This more or less leads to why fractional numbers are not normally converted between bases. You will lose precision and it's not a small task. But essentially the algorithmic conversation is the same as for whole numbers, but instead of dividing the number by the base and using the remainder as your output, you multiply by the base and use the division as your output.

int decimalPart = ...; //for example, "375", represents .375 or 3/8
int magnitude = Math.pow(10, ("" + decimalPart).length());
int newBase = 2; //again, bases that don't divide into each other will be messy, like 7 and 10

StringBuilder out = new StringBuilder();
//The below should be limited for precision, or you may loop forever
while (decimalPart > 0) {
    decimalPart *= newBase;
    out.append(decimalPart / magnitude);
    decimalPart %= magnitude.
}
String result = sb.toString();
//"375" -> "011"
Rogue
  • 11,105
  • 5
  • 45
  • 71
  • You basically repeated my answer. – WJS Aug 14 '19 at 21:45
  • I typed the answer myself on a phone, it's just the reversal of the same process used to convert non-fractional numbers. I could say you just repeated that; it's not an inherently complex solution. Additionally most of my answer is explaining the math component. – Rogue Aug 16 '19 at 23:06