Подсчет цифр в поплавке - PullRequest
       28

Подсчет цифр в поплавке

4 голосов
/ 28 января 2010

Я следую некоторым учебникам для начинающих по OpenGL в c ++, но поскольку я начинал как программист на c #, это заставило меня воспринимать многие вещи как должное. Таким образом, моя проблема возникла, когда я отлаживал печать моего чтения FPS на выход. Я думаю, что этот метод был чем-то вроде DebugPrintString с моей головы, который взял символ *, и в основном я печатал «FPS: x». Я использовал scanf_s, чтобы поместить значение fps в массив символов, но в этом моя проблема. Насколько большим должен быть массив символов?

Позвольте мне остановиться подробнее: мои показания FPS хранятся в виде числа с плавающей запятой, поскольку кадры / секунды обычно не являются хорошим числом. Таким образом, мой номер может быть 60 или 59.12345. 60 потребуется только 2 байта, а 59.12345 потребуется 8 (1 за период). Поэтому я подумал: «О, хорошо, мне нужно посчитать количество цифр, нет проблем!» Мальчик был в шоке.

Я сделал метод подсчета цифр, подсчитать левую часть десятичного разряда было легко, просто сначала применил его как int, чтобы удалить десятичные точки и разделить на 10 (на самом деле, я думаю, что у меня был какой-то сдвиг и посчитайте, сколько раз я могу сделать это, пока не достигну 0. А теперь, чтобы посчитать цифры с правой стороны, я просто умножу на 10, вычту цифру и делаю это, пока она не достигнет нуля. Метод обычно возвращает 32, я думаю, что это было. Так что я WTF'd и посмотрел на это в отладке, получается, когда вы умножаете число с плавающей точкой, эффективно перемещая столбцы цифр вверх из-за хорошо известной проблемы точности, он просто добавил еще одну цифру!

Я сделал несколько основных поисковиков, но не смог найти ничего, кроме char str [128] и scanf, если затем выполнить strlen (str) минус 1 (нулевой терминатор). Но я надеялся на более элегантное решение. В конце я просто преобразовал его в int и допустил 9999 кадров в секунду, также добавил проверку, чтобы увидеть, будет ли fps> 9999, но я не думаю, что это когда-нибудь произойдет. Лучше безопасно, чем SEG FAULT: (

TLDR: есть ли способ получить количество цифр в поплавке? Как Scanf делает это?!

Извините за длинный пост, просто хотел поделиться своим разочарованием>: D

Редактировать: орфографические ошибки

Ответы [ 5 ]

7 голосов
/ 28 января 2010

Учитывая, что мы говорим о C ++, почему бы не пойти по пути STL?

Точность 5 знаков после запятой, может быть разным количеством символов:

std::stringstream ss;
ss << std::setprecision (5) << std::fixed << f; 
std::string fps = ss.str();

Точность не более 5 значащих цифр:

std::stringstream ss;
ss << std::setprecision (5) << f; 
std::string fps = ss.str();
6 голосов
/ 28 января 2010

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

1 голос
/ 28 января 2010

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

С помощью printf(), scanf() и связанных функций размер числа с плавающей запятой можно указать, изменив спецификатор типа формата. Хотя простой %f может быть наиболее распространенным, его можно использовать более гибко, добавив модификаторы между % и f, такие как:

%[width][.precision]f

, где [width] относится к минимуму количеству цифр, отображаемому для числа (не будет усечения, если оно будет повторено), а [.precision] указывает точное количество цифр для отображения после десятичная точка.

В качестве примера вы можете проверить вывод следующей программы:

#include <cstdio>

using std::printf;
int main() {
  float f(59.12345);

  printf("[%f]\n", f);    // [59.123451]
  printf("[%15f]\n", f);  // [      59.123451]
  printf("[%1f]\n", f);   // [59.123451]
  printf("[%.2f]\n", f);  // [59.12]
  printf("[%6.2f]\n", f); // [ 59.12]
  printf("[%4.1f]\n", f); // [59.1]
}

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

0 голосов
/ 28 января 2010

Ну Джон из CashCommons дал традиционный ответ, просто используйте спецификаторы формата printf, чтобы задать определенную ширину. Я обычно нахожу, что 2 десятичных знака достаточно для частоты кадров. Он позволяет различать 30 к / с и 29,97 к / с, два наиболее распространенных значения.

 sprintf (buffer, "%.2f", fps);

Но если вы хотите знать, какой будет худший случай, есть и способ узнать это. Оформить заказ http://en.wikipedia.org/wiki/IEEE_754-2008.

Это показывает, что значения с плавающей запятой (32-битные числа с плавающей запятой) имеют 24 двоичные цифры в мантиссе, которая работает до 7,225 десятичных цифр, назовите ее 8. Добавьте 5 цифр для показателя степени, 1 для знака, 1 для ведущего 0, 1 для десятичной точки, и вы получите

 1 + 1 + 8 + 5 = 15 characters

добавьте место для завершающего нуля, и вы получите 16 цифр.

0 голосов
/ 28 января 2010

Это кадров в секунду. Просто используйте три цифры слева и одну справа, кого волнует, что происходит с представлением с плавающей запятой, что оно существует ниже десятой позиции?

РЕДАКТИРОВАТЬ в ответ на первый комментарий.

http://en.wikipedia.org/wiki/Floating_point

Если мы действительно после числа цифр в поплавке, мы должны знать, как работают поплавки. Точное значение, представленное в стандартном типе данных с плавающей запятой IEEE, имеет определенное количество битов, обычно 32 или 64, которые распределяются стандартным образом, чтобы дать вам набор значащих цифр, и некоторую степень степени для увеличения или уменьшения. 24 бита значащих цифр выходят до семи знаков после запятой. В конце курса всегда будет какая-либо форма усечения или ошибки округления (например, как одна треть, записанная в десятичном формате, всегда округляется, когда вы прекращаете писать повторяющиеся тройки).

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

...