Вопрос

Я следую некоторым руководствам для начинающих по 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 и посмотрел на это в debug, оказывается, когда вы умножаете значение с плавающей точкой, эффективно перемещая столбцы цифр вверх из-за хорошо известной проблемы с точностью, оно просто добавляет еще одну цифру!

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

TLDR ( ДВУ ):Есть ли способ получить количество цифр в переменной с плавающей точкой?Как scanf это делает?!

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

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

Это было полезно?

Решение

Учитывая, что мы говорим о 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();

Другие советы

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

Поскольку числа с плавающей запятой не хранятся каким-либо точным образом, на самом деле не существует какого-либо эффективного способа подсчета количества цифр.Что вы, вероятно, хотите сделать, это контролировать длину числа, предоставляемого 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]
}

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

Что ж Джон из 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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top