Counting numbers in a float

I follow some beginner tutorials for OpenGL in C ++, but when I started programming in C #, it made me take a lot of things for granted. So my problem arose when I was debugging the printing of my FPS readout output. I think the method was something like DebugPrintString from the top of the head, which took char *, and basically I printed "FPS: x". I used scanf_s to put the fps value in an array of characters, but this is where my problem is. How large should the character array be?

Let me tell you in more detail: FPS reading is stored as a float, since frames / seconds usually end with a bad number. So my number could be 60, or it could be 59.12345. 60 will require only 2 bytes, and 59.12345 - 8 (1 per period). So I thought: "Oh, well, I need to count the number of digits, no problem!" The boy was shocked.

I made a method of counting numbers, counting the left side of the decimal place, it was simple, just first of all, throw it as an int to remove the decimal points and divide by 10 (in fact, I think I had some bit offset there) and count the number of times I can do this until it reaches 0. And now, to count the numbers on the right side, well, I just multiply by 10, subtract the number and do it until it reaches zero. The method usually returns 32, I think it is. So, I am WTF'd and looked at it in debugging, it turns out that when you multiply a float, effectively moving the columns of digits due to a known accuracy problem, it just added another digit!

I did some major searches, but couldn't 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 ran it as an int and allowed enough for 9999 frames per second, also added a check to find out if there are fps> 9999, but I don’t think it will ever happen. Safer than SEG FAULT: (

TL; DR: is there a way to get the number of digits in a float? How does scanf do this ?!

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

Edit: spelling errors

+4
source share
5 answers

Given this C ++, which we are talking about, why not go the STL path?

The accuracy of 5 places after the decimal point can be a variable number of characters:

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

Precision maximum of 5 significant digits:

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

You can crop / force a floating point number to any precision you need with sprintf. Then the problem goes away.

+6
source

Since floating point numbers are not stored exactly, there is no efficient way to count the number of digits. What you probably want to do is control the length of the number that the float provides, and use a fixed size buffer.

With printf() , scanf() and related functions, you can specify the size of a floating-point number by changing the format type specifier. Although simple %f may be the most common, it can be used more flexibly by adding modifiers between % and f , for example:

 %[width][.precision]f 

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

As an example, you can check 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 will still be variable depending on the value to decimal. But while you can control the width and precision, allocating enough memory to an array of characters (or setting a number to an array with a fixed length) should be much simpler.

+1
source

These are frames per second. Just use three digits on the left and one on the right, who cares about what seems to be thinking of a floating point, exists below tenth?

EDIT in response to the first comment.

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

If we are really after the number of digits in the float, we need to know how the floats work. The exact value represented by the IEEE standard float data type has a certain number of bits, usually 32 or 64, which are standardly allocated to give you a certain number of significant digits, as well as some power indicator to scale it up or down. 24 bits of significant digits go into about seven places in decimal places. At the end of the course, there will always be some form of truncation or rounding error (for example, as one third, written in decimal, is always rounded when you stop writing repeated triples).

Maybe your number stops after seven or eight digits, but the rounding error of the machine keeps it accidental? It just doesn't make sense to read such data.

0
source

Ok John at CashCommons gave the traditional answer, just use printf format qualifiers to force a specific width. Usually I find that 2 decimal places is enough for the frame rate. 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 is, it is also a way to find out. Checkout http://en.wikipedia.org/wiki/IEEE_754-2008 .

It shows that floating point values ​​(32-bit floats) contain 24 binary digits in the mantissa that work up to 7,255 decimal digits, name it 8. Add 5 digits for the metric, 1 for the sign, 1 for the leading 0, 1 for the decimal points and you get

  1 + 1 + 8 + 5 = 15 characters 

add space for trailing zero and you get 16 digits.

0
source

Source: https://habr.com/ru/post/1299604/


All Articles