Extracting individual digits from a float

2019-07-17 16:22发布

问题:

I have been banging my head on this one all day. The C++ project I am currently working on has a requirement to display an editable value. The currently selected digit displays the incremented value above and decremented value below for said digit. It is useful to be able to reference the editable value as both a number and collection of digits. What would be awesome is if there was some indexable form of a floating point number, but I have been unable to find such a solution. I am throwing this question out there to see if there is something obvious I am missing or if I should just roll my own.


Thanks for the advice! I was hoping for a solution that wouldn't convert from float -> string -> int, but I think that is the best way to get away from floating point quantization issues. I ended up going with boost::format and just referencing the individual characters of the string. I can't see that being a huge performance difference compared to using combinations of modf and fmod to attempt to get a digit out of a float (It probably does just that behind the scenes, only more robustly than my implementation).

回答1:

Internal representation of the float point numbers aren't like was you see. You can only cast to a stirng.

To cast, do this:

char string[99];
sprintf(string,"%f",floatValue);

Or see this : http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.1

The wikipedia article can explain more on the representation: http://en.wikipedia.org/wiki/Floating_point



回答2:

Oh, there are many ways to convert to a string. (Though I do prefer snprintf() myself.)

Or you could convert to an int and pull the digits out with modulus and integer-division. You can count the number of digits with log{base10}.

(Remember: log{baseA}_X / log{baseA}_B = log{baseB}_X.)

Example:

#define SHOW(X) cout << # X " = " << (X) << endl

int
main()
{
  double d = 1234.567;

  SHOW( (int(d)%10000) / 1000 );
  SHOW( (int(d)%1000)  / 100  );
  SHOW( (int(d)%100)   / 10   );
  SHOW( (int(d)%10)           );
  SHOW( (int(d*10)  % 10)     );
  SHOW( (int(d*100) % 10)     );
  SHOW( (int(d*1000)% 10)     );

  SHOW( log(d)/log(10) );
}

Though you ought to use static_cast...

Watch out for exponential notation. With a very big or very small numbers, you may have a problem.

Floating point numbers also have round off issues that may cause you some grief. (It's the same reason why we don't use operator== between two doubles. Or why you can't rely on a*b == b*a. Depending on the exact values of a & b, they may differ very slightly out around 10^-25.)



回答3:

You can cast between string and float only by using boost::lexical_cast. However, you can't directly index the float form - it's internally not stored as decimal digits. This is probably not that much of an issue. For your UI, you will most likely keep a string form of the number anyway, with conversions to and from float in the getter/setter.