English 中文(简体)
Counting digits in a float
原标题:

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

最佳回答

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();
问题回答

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

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]
", f);    // [59.123451]
  printf("[%15f]
", f);  // [      59.123451]
  printf("[%1f]
", f);   // [59.123451]
  printf("[%.2f]
", f);  // [59.12]
  printf("[%6.2f]
", f); // [ 59.12]
  printf("[%4.1f]
", 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.

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.

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.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签