2013-10-24 3 views
1
var x = dr["NationalTotal"].ToString(); 

дает мне 333333333C# строка для преобразования с плавающей точкой недействительна?

var xxx = Convert.ToSingle(dr["NationalTotal"].ToString()); 

дает мне 333333344

Любые идеи, почему?

+0

Вы не должны вызывать 'ToString()'. (это ничего не исправит) – SLaks

+0

Мне нужно это в поплавке поплавать nationalTotal = dr ["NationalTotal"]. ToString(). Trim() == ""? 0.0f: Convert.ToSingle (dr ["NationalTotal"]. ToString()); – punkouter

+0

Сравните с 'DBNull.Value' не пустую строку. – Romoku

ответ

3

В спецификации с плавающей точкой говорит о том, что 32-битное представление числа с плавающей точкой является

enter image description here

Таким образом, наибольшее целое число, которое может быть представлено без потери (целое число) точности 16777216 (0x1000000) , Простая тестовая программа, чтобы убедить вас, что это так:

#include <stdio.h> 

int main(void) { 
    float x; 
    unsigned long j; 
    j = 0x00FFFFFC; 
    int i; 
    x = j; 
    for(i=0; i<10;i++) printf("%ld + %d = %f\n", j, i, x+i); 
} 

Выход:

16777212 + 0 = 16777212.000000 
16777212 + 1 = 16777213.000000 
16777212 + 2 = 16777214.000000 
16777212 + 3 = 16777215.000000 
16777212 + 4 = 16777216.000000 
16777212 + 5 = 16777216.000000 <<< from here on, adding one more doesn't give the right answer 
16777212 + 6 = 16777218.000000 
16777212 + 7 = 16777220.000000 
16777212 + 8 = 16777220.000000 
16777212 + 9 = 16777220.000000 

EDIT На основе комментариев под ним вопрос, мы медленно сходились на том, что вы были два вопроса , Не один.

Первое: «Почему это происходит?» ответил выше. Один float просто не может точно представить 333333333, поэтому вы получите ближайшее представимое значение, которое равно 333333344.

Второе: «Как это исправить?» первоначально ответила мне в комментариях - я повторю мой ответ здесь:

Вашего базы данных число с плавающей запятой обычно не одинарная точность - на самом деле, по умолчанию это двойная точность. Таким образом, можно решить проблему путем преобразования строки удвоить, и присваиваем его переменной двойной точности:

double xxx = Convert.ToDouble(dr["NationalTotal"]); 

Я хотел бы направить вас к http://floating-point-gui.de/ - «то, что каждый программист должен знать о плавающей точкой». На самом деле существует множество путеводителей с похожими именами. Основное чтение, если вы когда-либо отклонились от использования только целых чисел (и большинство людей в какой-то момент своей карьеры программирования).

6

Это происходит потому, что Single не имеет достаточной точности для хранения вашего полного номера.

Double имеет больше точности.

+0

+1 Вы правы. С тех пор я удалил свой ответ! – gleng

4

Из документов для System.Single:

Всех чисел с плавающей точкой имеет ограниченное число значащих цифр, которое также определяет, насколько точно значение с плавающей точкой аппроксимирует реальное число. Двойное значение имеет до 7 десятичных цифр точности, хотя не более 9 цифр поддерживается внутри.

Это фактически означает, что Single здесь, а не Double, но дело в том, что вы пытаетесь использовать его для 9 значащих цифр, и это не гарантированно доступны. Вы можете увидеть это очень легко, без разбора: (. «Г» является «туда-обратно» формат спецификатора)

float f = 333333333f; 
Console.WriteLine("{0:r", f); // Prints 333333344 

Другими словами, самое близкое float значение точного десятичного значения 333333333 is 333333344.

Если бы вы использовали Double, это, вероятно, сохранило бы все цифры, но это не значит, что это правильный подход. Это зависит от значения. Действительно ли это всегда целое число? Возможно, вы должны использовать long. Это нецелые, но финансовые данные (или какое-то другое «искусственное» значение)? Если да, рассмотрите возможность использования decimal.

Кроме того, почему вам нужно преобразовать это в строку и проанализировать ее? Каков тип времени выполнения dr["NationalTotal"]? Вы можете просто бросить - избегайте использования конверсий строк, в которых вам не нужно.

+0

его переход от преобразования сетки excel к datatable с использованием IExcelDataReader DataSet AsDataSet(); ... Я предположил, что все ячейки были строками .. может быть, я ошибаюсь .. плохой check – punkouter

+0

ой .. вы правы .. это на самом деле [System.RuntimeType] = {Name = "Double" FullName = "System.Double"} ... но мне нужно преобразовать это в float .. – punkouter

+0

@punkouter: Если вам нужно преобразовать в 'float', float' не имеет столько информации, сколько вам нужно, у вас проблемы. Но вы можете просто сбрасывать: 'var x = (float) (double) dr [" NationalTotal "];' - вам нужно бросать дважды, потому что приведение к 'double' просто распаковывается. –

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