2014-12-01 3 views
14

У меня есть большое число в шестнадцатеричном формате (с десятичной точкой) в String и я хочу, чтобы преобразовать его в BigDecimal.Как преобразовать большое шестнадцатеричное число (с десятичной точкой) для BigDecimal

Примера значение: 0xcc.ccdp+1600

в BigDecimal классе, я не вижу какой-либо функции, которая принимает строку, представляющую число в шестнадцатеричном формате в качестве входных данных и возвращает соответствующий BigDecimal.

есть ли способ, чтобы преобразовать большую шестнадцатеричное число от String до BigDecimal?

+0

Да, определенно есть путь. Если вам нужен способ, который не требует самостоятельного анализа входной строки, то я не уверен. Я не вижу никаких методов «BigDecimal», которые принимают любые входные данные в любом радиксе, кроме десятичного. – ajb

+0

Вы всегда можете отскакивать через 'BigInteger' ... анализировать обе стороны десятичной и затем конкатенировать и анализировать. Вероятно, есть несколько интересных способов сделать это в цифровом виде или подклассифицировать BigDecimal для изменения символьного отображения. –

+1

Обратите внимание, что теоретически это не «десятичная точка», а скорее «шестнадцатеричная точка». –

ответ

6

Я удивлен, что BigDecimal этого не поддерживает. Я написал следующее, которое, я думаю, должно работать. Она проходит мои первоначальные испытания (с 0xcc.ccdp+0, 0xcc.ccdp+1, 0xcc.ccdp+16, 0xcc.ccdp+256, и ваш 0xcc.ccdp+1600, а также некоторые отрицательными показателями, от -1 вплоть до -16), но она должна быть проверена более тщательно перед использованием в производстве код.

private final static BigInteger TWO = BigInteger.valueOf(2); 
private final static BigDecimal MINUS_ONE = new BigDecimal(-1); 

public static BigDecimal toBigDecimal(String hex) { 
    // handle leading sign 
    BigDecimal sign = null; 
    if (hex.startsWith("-")) { 
     hex = hex.substring(1); 
     sign = MINUS_ONE; 
    } else if (hex.startsWith("+")) { 
     hex = hex.substring(1); 
    } 

    // constant must start with 0x or 0X 
    if (!(hex.startsWith("0x") || hex.startsWith("0X"))) { 
     throw new IllegalArgumentException(
       "not a hexadecimal floating point constant"); 
    } 
    hex = hex.substring(2); 

    // ... and end in 'p' or 'P' and an exponent 
    int p = hex.indexOf("p"); 
    if (p < 0) p = hex.indexOf("P"); 
    if (p < 0) { 
     throw new IllegalArgumentException(
       "not a hexadecimal floating point constant"); 
    } 
    String mantissa = hex.substring(0, p); 
    String exponent = hex.substring(p+1); 

    // find the hexadecimal point, if any 
    int hexadecimalPoint = mantissa.indexOf("."); 
    int hexadecimalPlaces = 0; 
    if (hexadecimalPoint >= 0) { 
     hexadecimalPlaces = mantissa.length() - 1 - hexadecimalPoint; 
     mantissa = mantissa.substring(0, hexadecimalPoint) + 
      mantissa.substring(hexadecimalPoint + 1); 
    } 

    // reduce the exponent by 4 for every hexadecimal place 
    int binaryExponent = Integer.valueOf(exponent) - (hexadecimalPlaces * 4); 
    boolean positive = true; 
    if (binaryExponent < 0) { 
     binaryExponent = -binaryExponent; 
     positive = false; 
    } 

    BigDecimal base = new BigDecimal(new BigInteger(mantissa, 16)); 
    BigDecimal factor = new BigDecimal(TWO.pow(binaryExponent)); 
    BigDecimal value = positive? base.multiply(factor) : base.divide(factor); 
    if (sign != null) value = value.multiply(sign); 

    return value; 
} 

У меня есть released this on github под лицензией MIT. Есть модульные тесты, но только довольно минимальный набор.

Если вы найдете какие-либо случаи, для которых это возвращает неправильное значение, сообщите мне.

+1

Спасибо за предоставление решения. Я сделал некоторые начальные испытания, и код работал отлично. Единственный случай, о котором я могу сейчас думать, - это когда число, хранящееся в String, является отрицательным числом. Пример -0xcc.ccdp + 1600. Но нетрудно добавить чек для этого. – user2888308

+0

Упс! Я пропустил это. Хороший улов! –

+0

Я обновил его для обработки отрицательных чисел. Так как 'Integer.parseInt()' также может принимать ведущий унарный плюс, например, '' +42 ", я также не учитывал знак« впереди ». –

Смежные вопросы