2012-06-29 1 views
0

Я хочу точно проанализировать целое число, которое было потенциально отформатировано в соответствии с текущей локалью. Если бы я не разбирал целое число точно, я хочу это знать. Поэтому я использую:Обнаруживать неточность номера NumberFormat

String string = "1111122222333334444455555"; 
Locale locale = Locale.getDefault(); 
NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale); 
numberFormat.setParseIntegerOnly(); 
Number number = numberFormat.parse(string); 

Очевидно "1111122222333334444455555" представляет собой большое число, большее, чем Long может справиться. Так NumberFormat дает мне ... a Double ??

Я предполагаю, что я ожидал получить BigInteger, а не Double, тем более что я попросил форматировать числовые числа. Но не обращайте на это внимания; большая проблема заключается в том, что двойное значение, которое я получаю, это 1.1111222223333344E24! Это не равно 1111122222333334444455555 !!

Если NumberFormat дает мне разобранное значение, которое делает не равным тому, что хранится во входной строке, как это обнаружить?

Путь другой: «Как я могу узнать, имеет ли значение Double значение, полученное от NumberFormat, в точности эквивалентно интегральному значению, представленному в исходной строке?»

+1

Если вы используете простой 'Long.parseLong()', вы получите исключение переполнения. –

+1

Почему бы просто не построить BigInteger со строкой ввода вместо того, чтобы пытаться его разобрать? –

+0

@MarkoTopolnik, мне нужно поддерживать значения, которые, возможно, были отформатированы в текущем локальном (например, «1,234» в США). Я обновил вопрос, чтобы отразить это. –

ответ

0

javadocs для parse() заявить, что он вернет длинный, если возможно, в противном случае он вернет Двойной. Поэтому просто проверьте, чтобы возвращаемое значение было длинным.

«Возвращает длинный, если возможно, (в пределах диапазона [Long.MIN_VALUE, Long.MAX_VALUE] и без десятичных знаков), в противном случае -« Двойной ».

«Как узнать, является ли двойное значение, возвращаемое из NumberFormat, в точности эквивалентным интегральному значению, представленному в исходной строке?»

Если она возвращает распашные, то не точно соответствует вашему интегральному значению, так как Double не может точно представлять значения на эту величину. Конкретный пример:

Number a = numberFormat.parse("-9223372036854775809"); // Integer.MIN_VALUE - 1 
    Number b = numberFormat.parse("-9223372036854775810"); // Integer.MIN_VALUE - 2 
    System.out.println((a.equals(b))); // prints "true" 
    Number c = numberFormat.parse("-9223372036854776800"); 
    System.out.println((a.equals(c))); // prints "true" 
+0

Мое название было недостаточно ясно. То, что я действительно хочу обнаружить, - это то, будет ли возвращаемое значение точно отражать значение в строке. Поэтому, если возвращается «double», который содержит значение «Long.MIN_VALUE + 1», это нормально, если это то, что было в строке. Но как узнать, вернулось ли значение, что действительно было в строке? –

+1

@GarretWilson Учитывайте это: 'long' охватывает все возможные знаковые целые числа, которые могут быть точно представлены 64 битами. Когда 'long' переполняется, это будет уже много и много целых чисел за последнюю точку, где последовательные« двойные »значения по-прежнему могут покрывать последовательные целые числа (то есть, могут точно представлять эти целые числа после округления). –

+0

@MarkoTopolnik Это интересное замечание, но я не уверен, как он отвечает на вопрос: «Как я могу узнать, что значение« double », которое я возвращаю из« NumberFormat », в точности эквивалентно интегральному значению, представленному в оригинале строка?» Я говорю не только о переполнении; извините за путаницу --- Я отредактировал название. –

0

Для вас вопрос -

If NumberFormat gives me a parsed value that does not equal that stored in the input string, how do I detect that? 

Вы можете использовать

if(number.toString().equals(string)) 
     //Parsed correctly 
    else 
    //Invalid parse 
+1

хорошая идея, но это не зависит от языка. 'number.toString()' не зависит от локали, но 'numberFormat.parse()' чувствителен к региону, и ему нужна процедура, которая будет работать с учетом языка. – Enwired

+0

Я думаю, что это не то, что ищет OP. –

0

Это не может быть решением, но стоит уведомление.

public static void main(String[] args) { 
     String string = "1111122222333334444455555"; 
     Locale locale = Locale.getDefault(); 
     NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale); 
     numberFormat.setParseIntegerOnly(true); 
     Number number = numberFormat.parse(string); 
     BigDecimal b = new BigDecimal(number.toString()); 
     System.out.println(b.toBigInteger()); 

    } 

Выход этого кода: 1111122222333334400000000

Как вы можете видеть, что это не равно числу в реальной строке, так что их может быть переполнение occoured.

+0

Я не вижу, как этот код отвечает на вопрос. Может создать метод, который вводит 'String' и возвращает' Number', и если результирующее число не совпадает со значением в исходной строке, оно выдает исключение? Я не понимаю, как это делает код. –

+0

То, что я делаю в этом коде, - это преобразование 1.1111222223333344E24 (разобранное) в bigInteger, чтобы мы могли сравнить его с исходным числом, которое находится в строковой форме. –

+0

Да, но вы обнаружите, что он не будет работать с входными представлениями, специфичными для локали, такими как «1,234» или «1.234». –