Работа с большими целыми числами

Я создаю программу, в которой она принимает базовую единицу в метрической системе. (Скажем граммы.) А потом при выборе префикса меняет его на эквивалентную сумму. (Например, 1000 граммов, когда вы выбираете килограмм, изменятся на 1 килограмм.)

Проблема в том, что когда я запускаю код, он всегда заканчивается нулем, что заставляет меня думать, что я неправильно манипулирую BigIntegers. (Я использую ОЧЕНЬ большие числа из-за того, что некоторые префиксы очень маленькие или очень большие по сравнению с обычным длинным числом.)

Вот код:

import java.util.Scanner;
import java.math.BigInteger;

public class BaseMetricUnits {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("Hello, World!");
    float meter = 1;
    float kilogram = 1;
    float second = 1;
    float ampere = 1;
    float kelvin = 1;
    float mole = 1;
    float candela = 1;
    PrefixConverter();
}
public static void PrefixConverter() 
{

    BigInteger Yocto = BigInteger.valueOf((long) 0.00000000000000000000000);
    BigInteger Zepto =  BigInteger.valueOf((long) 0.000000000000000000001);
    BigInteger Atto = BigInteger.valueOf((long) 0.000000000000000001);
    BigInteger Femto = BigInteger.valueOf((long) 0.000000000000001);
    BigInteger Pico = BigInteger.valueOf((long)0.000000000001);
    BigInteger Nano = BigInteger.valueOf((long)0.000000001);
    BigInteger Micro = BigInteger.valueOf((long)0.000001);
    BigInteger Milli = BigInteger.valueOf((long)0.001);
    BigInteger Centi = BigInteger.valueOf((long)0.01);
    BigInteger Deci = BigInteger.valueOf((long)0.1);
    BigInteger Deca = BigInteger.valueOf((long)10);
    BigInteger Hecto = BigInteger.valueOf((long)100);
    BigInteger Kilo = BigInteger.valueOf((long)1000);
    BigInteger Mega = BigInteger.valueOf((long)1000000);
    BigInteger Giga = BigInteger.valueOf((long)1000000000);
    BigInteger Tera = new BigInteger("1000000000000");
    BigInteger Peta = new BigInteger("1000000000000000");
    BigInteger Exa = new BigInteger("1000000000000000000");
    BigInteger Zetta = new BigInteger("1000000000000000000000");
    BigInteger Yotta = new BigInteger("1000000000000000000000000");

    long Amount;
    double Prefix; 
    String Units = "";
    BigInteger translatedResult;
    BigInteger Result;

    Scanner inputDevice = new Scanner(System.in);
    System.out.print("Please enter the type of unit to be used. (meters, grams, etc.) >> ");
    Units = inputDevice.next();
    System.out.print("Please enter an amount to be translated >> ");
    Amount = inputDevice.nextLong();
    System.out.print("Please choose one of the following Prefixes to translate to. ");
    System.out.print(" 1 - Yocto ");
    System.out.print(" 2 - Zepto ");
    System.out.print(" 3 - Atto ");
    System.out.print(" 4 - Femto ");
    System.out.print(" 5 - Pico ");
    System.out.print(" 6 - Nano ");
    System.out.print(" 7 - Micro ");
    System.out.print(" 8 - Milli ");
    System.out.print(" 9 - Centi ");
    System.out.print(" 10 - Deci ");
    System.out.print(" 11 - Deca ");
    System.out.print(" 12 - Hecto ");
    System.out.print(" 13 - Kilo ");
    System.out.print(" 14 - Mega ");
    System.out.print(" 15 - Giga ");
    System.out.print(" 16 - Tera ");
    System.out.print(" 17 - Peta ");
    System.out.print(" 18 - Exa ");
    System.out.print(" 19 - Zetta ");
    System.out.print(" 20 - Yotta ") ;
    Prefix = inputDevice.nextDouble();

     if(Prefix == 1)
     {
        Result = Yocto.multiply(BigInteger.valueOf(Amount));
        translatedResult = Yocto.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Yocto" + Units + ".");
     }
     if(Prefix == 2)
     {
        Result = Zepto.multiply(BigInteger.valueOf(Amount));
        translatedResult = Zepto.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Zepto" + Units + ".");
     }
     if(Prefix == 3)
     {
        Result = Atto.multiply(BigInteger.valueOf(Amount));
        translatedResult = Atto.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Atto" + Units + ".");
     }
     if(Prefix == 4)
     {
        Result = Femto.multiply(BigInteger.valueOf(Amount));
        translatedResult = Femto.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Femto" + Units + ".");
     }
     if(Prefix == 5)
     {
        Result = Pico.multiply(BigInteger.valueOf(Amount));
        translatedResult = Pico.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Pico" + Units + ".");
     }
     if(Prefix == 6)
     {
        Result = Nano.multiply(BigInteger.valueOf(Amount));
        translatedResult = Nano.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Nano" + Units + ".");
     }
     if(Prefix == 7)
     {
        Result = Micro.multiply(BigInteger.valueOf(Amount));
        translatedResult = Micro.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Micro" + Units + ".");
     }
     if(Prefix == 8)
     {
        Result = Milli.multiply(BigInteger.valueOf(Amount));
        translatedResult = Milli.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Milli" + Units + ".");
     }
     if(Prefix == 9)
     {
        Result = Centi.multiply(BigInteger.valueOf(Amount));
        translatedResult = Centi.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Centi" + Units + ".");
     }
     if(Prefix == 10)
     {
        Result = Deci.multiply(BigInteger.valueOf(Amount));
        translatedResult = Deci.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Deci" + Units + ".");
     }
     if(Prefix == 11)
     {
        Result = Deca.multiply(BigInteger.valueOf(Amount));
        translatedResult = Deca.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Deca" + Units + ".");
     }
     if(Prefix == 12)
     {
        Result = Hecto.multiply(BigInteger.valueOf(Amount));
        translatedResult = Hecto.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Hecto" + Units + ".");
     }
     if(Prefix == 13)
     {
        Result = Kilo.multiply(BigInteger.valueOf(Amount));
        translatedResult = Kilo.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Kilo" + Units + ".");
     }
     if(Prefix == 14)
     {
        Result = Mega.multiply(BigInteger.valueOf(Amount));
        translatedResult = Mega.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Mega" + Units + ".");
     }
     if(Prefix == 15)
     {
        Result = Giga.multiply(BigInteger.valueOf(Amount));
        translatedResult = Giga.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units +  " which translates to " + translatedResult + "Giga" + Units + ".");
     }
     if(Prefix == 16)
     {
        Result = Tera.multiply(BigInteger.valueOf(Amount));
        translatedResult = Tera.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Tera" + Units + ".");
     }  
     if(Prefix == 17)
     {
        Result = Peta.multiply(BigInteger.valueOf(Amount));
        translatedResult = Peta.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Peta" + Units + ".");
     }
     if(Prefix == 18)
     {
        Result = Exa.multiply(BigInteger.valueOf(Amount));
        translatedResult = Exa.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Exa" + Units + ".");
     }
     if(Prefix == 19)
     {
        Result = Zetta.multiply(BigInteger.valueOf(Amount));
        translatedResult = Zetta.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Zetta" + Units + ".");
     }
     if(Prefix == 20)
     {
        Result = Yotta.multiply(BigInteger.valueOf(Amount));
        translatedResult = Yotta.divide(BigInteger.valueOf(Amount));
        System.out.println("You have " + Result + " " + Units + " which translates to " + translatedResult + "Yotta" + Units + ".");
     }
     else
     {
        System.out.println("Not a valid input.");
     }
    }
}

Спасибо за вашу помощь.


person dpolaristar    schedule 05.10.2015    source источник
comment
(long) 0.000000000000000000001 == 0L и т. д. Приведение в основном принимает целую часть числа. Есть ли веская причина, по которой вы не использовали "0.000000000000000000001", как для Tera, Peta и т. д.? Или BigInteger.ONE.shiftRight/Left?   -  person Andy Turner    schedule 06.10.2015
comment
Я только что понял, что перепутал методы умножения и деления, и, как говорится, некоторые ответы по-прежнему равны 0.   -  person dpolaristar    schedule 06.10.2015
comment
@AndyTurner на меньших числах, таких как первый BigInteger Yocto, например, выдает мне эти странные ошибки. Исключение в потоке main java.lang.NumberFormatException: для входной строки: .00000 в java.lang.NumberFormatException.forInputString(неизвестный источник) в java.lang.Integer.parseInt(неизвестный источник) в java.math.BigInteger.‹init› (Неизвестный источник) в java.math.BigInteger.‹init›(Неизвестный источник) в BaseMetricUnits.PrefixConverter(BaseMetricUnits.java:21) в BaseMetricUnits.main(BaseMetricUnits.java:16) Как эти.   -  person dpolaristar    schedule 06.10.2015
comment
Почему вы используете BigInteger, а не BigDecimal для дробей? BigInteger может хранить только целые числа.   -  person Patricia Shanahan    schedule 06.10.2015
comment
А если использовать сменные методы?   -  person Andy Turner    schedule 06.10.2015
comment
@PatriciaShanahan ‹facepalm› за то, что не заметила этого.   -  person Andy Turner    schedule 06.10.2015
comment
@PatriciaShanahan Если вы посмотрите на код, он выдаст ответ как Результат и переведенный Результат. Если я не смогу придумать способ сделать его либо BigInteger, либо BigDecimal в зависимости от контекста, окончательный ответ может быть одним или другим. Я беспокоюсь, если пользователь захочет попытаться перевести один грамм, скажем, в йоттаграмму, а затем ответ BigInteger застрянет в ошибке при попытке сохранить десятичное число и наоборот.   -  person dpolaristar    schedule 06.10.2015
comment
@AndyTurner, какие методы смены?   -  person dpolaristar    schedule 06.10.2015
comment
@dpolaristar Вы не можете заставить BigInteger выполнять работу BigDecimal. Если ответ является целым числом, и вы хотите, чтобы он сообщался как таковой, вы можете использовать toBigInteger или toBigIntegerExact BigDecimal.   -  person Patricia Shanahan    schedule 06.10.2015
comment
Есть ли способ динамически сделать его результатом или переведенным результатом, чтобы сохранить ответ как BigDecimal или BigInteger в зависимости от того, какой ответ выходит для математики. (Пользователь может попытаться превратить 1 грамм в 0,000000000000000000000000 йотта-граммов, например, что делает неуместным хранение в виде BigInteger, но также было бы неуместно хранить 100000000000000000000000000000000000 грамм в виде 1 йоктограмм в качестве BigDecimal. Хотя большинство пользователей может руководствоваться здравым смыслом, чтобы избежать этого, другие пользователи могут попытаться сломать программу.   -  person dpolaristar    schedule 06.10.2015
comment
Теперь я получаю сообщение об ошибке, когда идет Незаканчивающееся десятичное расширение; нет точного представимого десятичного результата. в java.math.BigDecimal.divide (неизвестный источник) Когда я пытаюсь выполнить арифметику.   -  person dpolaristar    schedule 06.10.2015
comment
@dpolaristar Сообщение об ошибке BigDecimal — это новая проблема. Прежде чем задать вопрос об этом, перечитайте документацию BigDecimal API, чтобы узнать, сможете ли вы понять, что происходит не так. Если вы публикуете, включите минимальную неисправную программу, иллюстрирующую проблему.   -  person Patricia Shanahan    schedule 07.10.2015


Ответы (1)


BigInteger может хранить только целые числа, поэтому он не подходит для этого приложения. Я настоятельно рекомендую заменить его на BigDecimal.

Вы также должны использовать строковые представления дробей для инициализации:

  BigDecimal Zepto =  new BigDecimal("0.000000000000000000001");
  BigDecimal Atto = new BigDecimal("0.000000000000000001");
  BigDecimal Femto = new BigDecimal("0.000000000000001");
  BigDecimal Pico = new BigDecimal("0.000000000001");
  BigDecimal Nano = new BigDecimal("0.000000001");

Комментарии к этому ответу и вопросу указывают на озабоченность по поводу использования BigDecimal для хранения больших чисел. Эта программа иллюстрирует тот факт, что это не проблема:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    BigDecimal googol = new BigDecimal("1e100");
    System.out.println(googol);
    System.out.println(googol.add(BigDecimal.ONE));
  }
}

Выход:

1E+100
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
person Patricia Shanahan    schedule 05.10.2015
comment
Если вы посмотрите на код, он выдаст ответ как Результат и переведенный Результат. Если я не смогу придумать способ сделать его либо BigInteger, либо BigDecimal в зависимости от контекста, окончательный ответ может быть одним или другим. Я беспокоюсь, если пользователь захочет попытаться перевести один грамм, скажем, в йоттаграмму, а затем ответ BigInteger застрянет в ошибке при попытке сохранить десятичное число и наоборот. – - person dpolaristar; 06.10.2015
comment
Почему вы хотите, чтобы Result был BigInteger? Это приведет к потере данных, если ответ не является целым числом. С другой стороны, BigDecimal может хранить все, что может хранить BigInteger. - person Patricia Shanahan; 06.10.2015
comment
Итак, я могу хранить все числа, даже большие, как BigDecimal? Я этого не знал. - person dpolaristar; 06.10.2015
comment
@dpolaristar Да, BigDecimal может обрабатывать очень большие числа, больше, чем вы используете. BigDecimal на самом деле является BigInteger, масштабируемым в степени десяти, чтобы обрабатывать десятичные дроби, а также целые числа. - person Patricia Shanahan; 06.10.2015