计算浮点数中的数字

发布于 2024-08-19 18:26:24 字数 886 浏览 5 评论 0原文

我正在关注一些 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 if in then do strlen(str) minus 1 (空终止符)之上的任何内容。但我希望有一个更优雅的解决方案。最后,我只是将其转换为 int 并允许足够的 9999 fps,还添加了一个检查以查看 fps > > 9999 但我认为这永远不会发生。比 SEG FAULT 更安全:(

TLDR: 有没有办法获取浮点数中的位数? scanf 是如何做到的?!

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

编辑:拼写错误

I am following some beginner tutorials for OpenGL in c++ but as I started off as a c# programmer it has made me take a lot of things for granted. So my problem occurred when I was debug printing my FPS reading to the output. I think the method was something like DebugPrintString off the top of my head which took a char* and basically i was printing "FPS: x". I was using scanf_s to place the fps value into the character array but this is where my problem lies. How big does the character array have to be?

Let me elaborate a bit more: my FPS reading is stored as a float as the frames/seconds usually ends up not being a nice number. So my number could be 60, or it could be 59.12345. 60 would only need 2 bytes and 59.12345 would need 8 (1 for the period). So I thought "Oh ok i need to count the amount of digits it has, no problem!" Boy was I in for a shock.

I made a method to count the digits, counting the left hand side of the decimal place was easy, just first of all cast it as a int to remove the decimal points and divide by 10 (actually I think I had some bitshifting there) and count the amount of times i can do that until i reach 0. And now to count the digits on the right hand side, well i'll just multiply by 10, subtract the digit, and do this until it reaches zero. The method would usually return 32 i think it was. So i WTF'd and had a look at it in debug, turns out when you multiply the float effectively moving the digit columns up because of the well known precision issue it just appended another digit!

I did some major googling, but couldn't really find anything above char str[128] and scanf if in then do strlen(str) minus 1 (null terminator). But i was hoping for a more elegant solution. In the end i just casted it as an int and allowed enough for 9999 fps, also added a check to see if the fps > 9999 but I don't think thats ever going to happen. Better safe than SEG FAULT :(

TLDR: Is there a way to get the amount of digits in a float? How does scanf do it?!

Sorry for long post, just wanted to share my frustation >:D

Edit: spelling errors

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

蓝天 2024-08-26 18:26:24

考虑到我们正在谈论的是 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();

Considering it's C++ we're talking about, why not go the STL way?

Precision 5 places after decimal dot, may be variable amount of characters:

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

Precision maximum 5 significant digits:

std::stringstream ss;
ss << std::setprecision (5) << f; 
std::string fps = ss.str();
我不吻晚风 2024-08-26 18:26:24

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

You can truncate/force the floating-point number to whatever precision you want using sprintf. Then the problem goes away.

可可 2024-08-26 18:26:24

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

使用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]
}

字符数组的确切大小仍然是可变的,具体取决于小数点之前的值。但只要您可以控制宽度和精度,为字符数组分配足够的内存(或将数字放入固定长度数组)应该会简单得多。

Since floating point numbers aren't stored in any precise manner, there's not really any effective way to count the number of digits. What you probably want to do is control the length of the number the float provides and use a buffer with a fixed size.

With printf(), scanf() and related functions, the size of a floating point number can be specified by modifying the format type specifier. While a simple %f may be the most common, it can be used more flexibly by adding modifiers between the % and the f, such as:

%[width][.precision]f

where [width] refers to the minimum number of digits to display for the number (there will be no truncation if it goes over), and [.precision] specifies the exact number of digits to display after the decimal point.

By way of example, you can examine the output of the following program:

#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]
}

The exact size of the character array would still be variable depending on the value before the decimal. But so long as you can control the width and the precision, allocating enough memory into a character array (or fitting the number into a fixed-length array) should be substantially simpler.

行雁书 2024-08-26 18:26:24

那么 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

为终止空添加空间,然后您将获得 16 位数字。

Well John at CashCommons gave the traditional answer, just use printf format qualifiers to force a certain width. I usually find that 2 decimal places is plenty for frame rates. It allows you to distinguish between 30 fps and 29.97 fps, the two most common values.

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

But if you want to know what the WORST case would be, theres a way to know that as well. Checkout http://en.wikipedia.org/wiki/IEEE_754-2008.

It shows that floating point values (32 bit floats) have 24 binary digits in the mantissa, that works out to 7.225 decimal digits, call it 8. Add 5 digits for the exponent, 1 for the sign, 1 for a leading 0, 1 for the decimal point and you get

 1 + 1 + 8 + 5 = 15 characters

add room for a terminating null and you get 16 digits.

凉城凉梦凉人心 2024-08-26 18:26:24

是每秒帧数。只需使用左侧三位数字和右侧一位数字,谁在乎浮点表示碰巧认为十位以下存在什么?

编辑回应第一条评论。

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

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

也许您的数字在七位或八位数字后停止,但机器舍入错误意外地让它继续下去?读取此类数据是没有意义的。

It's frames per second. Just use three digits on the left and one on the right, who cares what the floating point representation happens to think exists below the tenths place?

EDIT in response to the first comment.

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

If we're really after the number of digits in the float, we have to know how floats work. The exact value represented in the IEEE standard float datatype has a certain amount of bits usually 32 or 64, which are allocated in a standardized way to give you a set amount of significant digits, and some power exponent to scale it up or down. 24 bits of significant digits comes out to about seven places in decimals. There's always going to be some form of truncation or rounding error on the end of course (like how one third, written in decimal, always rounds down when you stop writing the repeating threes).

Maybe your number stops after seven or eight digits, but the machine rounding error keeps it going by accident? It just doesnt make sense to read that sort of data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文