проблема с литьем поплавка -> двойной в C, когда Fread - PullRequest
0 голосов
/ 16 июля 2010

У меня проблема с приведением от float к double при фреде;

fread(doublePointer,sizeofFloat,500,f);

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

Я знаю, что могу решить эту проблему, конвертировав ее один за другим.но у меня есть огромное количество данных.и я не хочу дополнительных 9000000+ раундов конвертации .. это было бы очень дорого.и есть ли какой-нибудь трюк, который я могу решить?

есть ли какие-нибудь трюки с ++ / c

спасибо

Ответы [ 4 ]

6 голосов
/ 16 июля 2010

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

3 голосов
/ 16 июля 2010

Предположим, например, что число с плавающей запятой на вашем компьютере составляет 4 байта.Если вы читаете 500 с плавающей запятой, то вы читаете 2000 байтов, по одному с плавающей запятой на число с плавающей запятой, и результат правильный.

Предположим, например, что на вашем компьютере значение типа double равно 8 байтам.Если вы читаете 500 с плавающей запятой, то вы читаете 2000 байтов, но вы читаете их по 250 двойных, 2 с плавающей запятой, и в результате получается бессмыслица.

Если ваш файл имеет 500 с плавающей запятой, вы должны прочитать 500 поплавков,Приведите каждое значение с плавающей запятой к двойному значению.Таким образом вы можете преобразовать каждое числовое значение.

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

Редактировать: Вы добавили в свой вопрос "и я не хочу лишний 9000000+ раунд конвертации ... это было бы очень дорого. И есть ли какой-нибудь трюк, который я могу решить?"Ответ - да, вы можете использовать трюк, чтобы ваши поплавки оставались поплавками.Если вы не хотите конвертировать в двойные числа, не конвертируйте в двойные, просто сохраняйте свои числа с плавающей точкой.

1 голос
/ 16 июля 2010

9000000 преобразований из числа с плавающей запятой в ничто - ничто. fread в массив float, затем преобразуйте его в массив double.

Оцените этот код с научной точки зрения, не думайте о том, где могут быть замедления.

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

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

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

Современное ядро ​​x86 способно выполнять два float->double преобразования за цикл в векторизованном цикле с ручной настройкой; при 2 ГГц это 4 миллиарда конверсий в секунду на ядро. 9 миллионов конверсий - это небольшое изменение - мой ноутбук делает это менее чем за 1 миллисекунду.


В качестве альтернативы, просто конвертируйте весь набор данных в двойной, и читайте его таким образом с этого момента. Проблема решена.

0 голосов
/ 16 июля 2010

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

Поэтому я бы выделил буфер для 500 (или чего-то еще) float с и считал их из данныхфайл с одним подходящим вызовом на fread():

float *databuffer;
//...
databuffer = malloc(500 * sizeof(float));
fread(databuffer, sizeof(Float), 500, f);

Позже, используйте данные в любой математике, в которой они должны участвовать. Они будут повышены до double, если потребуется.Не забудьте в конце концов освободить буфер после того, как он больше не нужен.

Если ваши результаты действительно имеют всю точность, равную double, то используйте новый буфер double s, чтобы удерживать их,Однако, если они должны быть записаны обратно в файл как float, вам, в конечном счете, нужно будет поместить их в буфер float s.

Обратите внимание, что для чтения и записи файлов для обмена часто требуетсяследует рассматривать как отдельную проблему от эффективного хранения и использования данных в памяти.Часто необходимо прочитать файл и каким-то образом обработать каждое отдельное значение.Например, переносная программа может потребоваться для обработки данных, записанных системой с использованием другого порядка байтов.Сегодня реже вы можете обнаружить, что даже расположение битов в float отличается в разных системах.В общем, эту проблему часто лучше всего решить, если обратиться к библиотеке, реализующей стандарт, такой как XDR (определенный RFC 4506 ), который был разработан для работы с двоичной переносимостью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...