4

我正在关注一些 C++ 中 OpenGL 的初学者教程,但是当我开始作为 ac# 程序员时,它让我认为很多事情是理所当然的。所以当我调试将我的 FPS 读数打印到输出时出现了我的问题。我认为该方法类似于我头顶上的 DebugPrintString,它需要一个 char* 并且基本上我正在打印“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 之上找不到任何内容,如果在 then 中执行 strlen(str) 减 1(空终止符)。但我希望有一个更优雅的解决方案。最后我只是将它转换为一个 int 并允许 9999 fps,还添加了一个检查以查看 fps > 9999 但我认为这不会发生。比 SEG FAULT 更安全 :(

TLDR:有没有办法获得浮点数的位数?scanf 是怎么做到的?!

抱歉发了很长的帖子,只是想分享我的挫败感>:D

编辑:拼写错误

4

5 回答 5

7

考虑到我们正在谈论的是 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();
于 2010-01-28T00:06:56.763 回答
6

您可以使用 sprintf 将浮点数截断/强制为所需的任何精度。然后问题就消失了。

于 2010-01-27T23:58:07.987 回答
1

由于浮点数没有以任何精确的方式存储,因此实际上没有任何有效的方法来计算位数。您可能想要做的是控制浮点数提供的长度并使用固定大小的缓冲区。

使用printf(),scanf()和相关函数,可以通过修改格式类型说明符来指定浮点数的大小。虽然 simple%f可能是最常见的,但可以通过在 the%和 the之间添加修饰符来更灵活地使用它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]
}

字符数组的确切大小仍然会根据小数点前的值而变化。但是只要您可以控制宽度和精度,将足够的内存分配到字符数组(或将数字放入固定长度的数组)应该会更简单。

于 2010-01-28T00:42:10.833 回答
0

它是每秒帧数。只需在左边使用三个数字,在右边使用一个数字,谁在乎浮点表示碰巧认为存在于十分位以下?

编辑以回应第一条评论。

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

如果我们真的想知道浮点数的位数,我们必须知道浮点数是如何工作的。IEEE 标准浮点数据类型中表示的确切值具有一定数量的位,通常为 32 或 64,这些位以标准化方式分配,为您提供一定数量的有效数字,以及一些幂指数来按比例放大或缩小。24 位有效数字大约为小数点后七位。当然,最后总会出现某种形式的截断或舍入错误(比如用十进制写的三分之一,当你停止写重复的三时总是向下舍入)。

也许您的号码在七八位数字后停止,但机器舍入错误使其意外运行?读取那种数据是没有意义的。

于 2010-01-28T00:20:15.307 回答
0

CashCommons的John给出了传统的答案,只需使用 printf 格式限定符来强制一定的宽度。我通常发现 2 位小数对于帧速率来说已经足够了。它允许您区分 30 fps 和 29.97 fps 这两个最常见的值。

 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 位数字。

于 2010-01-28T00:57:35.037 回答