0

I want to convert float to int removing decimal point, meaning if F = 2.521, conversion to int = 2521 What is the fast way to do this using C++?

G.Azma
  • 37
  • 9
  • 5
    `round(F * 1000.0)`. Note with `float F = 2.521;` , `F` is not _exactly_ 2.521. – chux - Reinstate Monica Jul 05 '21 at 02:34
  • 2
    Use strings. For the good fraction of floating point numbers, they cant be represented exactly: https://stackoverflow.com/questions/588004/is-floating-point-math-broken – NathanOliver Jul 05 '21 at 02:34
  • Further to the what chux said above, the rounding modes are: std::ceil, std::floor, std::trunc, or std::round. round is the most common, but might not be exactly what you need. – robthebloke Jul 05 '21 at 02:35
  • 1
    What's the source of these floats? Should `2.5` be mapped to `25` and `2.52` mapped to `252`? If so you might run into some precision issues where things that have a short exact representation in decimal _don't_ have one in binary. – Nathan Pierson Jul 05 '21 at 02:37
  • Hmm, strings are probably slow, but I like rounding method. – G.Azma Jul 05 '21 at 02:38
  • I want floats to be mapped to it's lowest decimal (not counting super low floating point errors) – G.Azma Jul 05 '21 at 02:38
  • Strings are slow... sometimes. Depends a lot on what you're going to do with them. I find that unless I'm doing arithmetic with numbers, strings work faster and easier. – user4581301 Jul 05 '21 at 02:43
  • @G.Azma: When you say "mapped to lowest decimal" do you mean "rounded towards negative infinity" (e.g. -5.250000000001 becomes -526) or "rounded towards zero" (e.g. -5.250000000001 becomes -525) or do you mean "not rounded in the first place" (e.g. -5.250000000001 becomes -5250000000001)? – Brendan Jul 05 '21 at 02:47
  • @G.Azma What if the value was 2.520999908447265625? This is a value `float` can exactly encode. Would you want `2520999908447265625` to print out as the integer or `2521` or `2520` or ??? – chux - Reinstate Monica Jul 05 '21 at 02:47
  • I want 2.515715 to print out 2515715, but 1.15151519581011 not, it's too low – G.Azma Jul 05 '21 at 02:52
  • @G.Azma A `float` cannot encode 2.515715. The nearest `float` is 2.5157148838043212890625. What should that print out? – chux - Reinstate Monica Jul 05 '21 at 02:55
  • Sorry, I am not familiar with how floats work, comment about rounding answered my question, I wanted to map float to int from start to end (8 decimal places, or something reasonable like that, so I can just multiply float by 1e8) – G.Azma Jul 05 '21 at 02:58
  • 1
    @G.Azma: Do you mean "no more than 8 fractional digits" (e.g. 123456789123456789.0 becomes 123456789123456789) or do you mean "no more than 8 significant digits (e.g. 123456789123456789.0 becomes 12345678)? Note that the former may cause problems with overflowing the resulting integer. – Brendan Jul 05 '21 at 03:00
  • 8 significant digits – G.Azma Jul 05 '21 at 03:02

3 Answers3

0

I have no idea if it's the fastest way (or merely "a way"), and haven't tested if it behaves as I intend (especially with regard to precision loss), but here's my attempt at "extract up to 8 significant decimal digits from float into integer, with trailing zero suppression and rounding towards zero"):

#include <math.h>

int32_t convert(float value) {
    double v = value;     // Need to increase size to reduce risk of precision loss
    int sign = 0;
    int32_t result = 0;
    int digit;

    // Extract sign and ensure v isn't negative

    if(v < 0) {
        sign = 1;
        v = -v;
    }

    // Reduce magnitude of v by dividing by 10 until it's between 0.0 and 1.0 (exclusive).

    while(v >= 100000000.0) {
         v /= 1000000000.0;
    }
    if(v >= 10000.0) {
         v /= 100000.0;
    }
    if(v >= 100.0) {
         v /= 1000.0;
    }
    if(v >= 10.0) {
         v /= 100.0;
    } else if(v >= 1.0) {
         v /= 10.0;
    }

    // Extract (up to) 8 significant digits from v while trying to avoid trailing zeros (e.g. the original value 1.2 would hopefully become 12 and not 12000000).

    for(int i = 0; (i < 8) && ((float)v > 0.0); i++) {
        digit = floor(v * 10);
        result = result*10 + digit;
        v = v * 10 - digit;
    }

    // Suppress any trailing zeros that slipped through due to precision losses

    while( (result != 0) && (result % 10 == 0) ) {
        result /= 10;
    }

    // Restore the original value's sign

    if(sign != 0) {
         result = -result;
    }

    // Done!

    return result;
}
Brendan
  • 35,656
  • 2
  • 39
  • 66
0

i did this with string input of float number.put the string chars into integer array except '.' and then convert integer array into decimal number in base 10.

#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main()
{
    string str="";
    cout<<"Enter num ?\n";
    cin>>str;
    int k = str.length()-1;
    int *a  = new int[k];
    int x=0;
    for(int i=0;i<str.length();i++)
    {
        if(str[i]!='.')
        a[x++] = (int(str[i]))-48;
        
    }
    long int res=0;
    x=0;
    for(int i=0;i<k;i++)
    {
        res+=a[k-1-i]*pow(10,x++);
    }
    cout<<"Integer is = "<<res<<endl;
}
Salar Ashgi
  • 128
  • 2
  • 13
  • `int *a = new int[k]` instead of `std::vector`, and no `delete[]` - this is not exactly a good example of C++ in the 21st century. – MSalters Jul 05 '21 at 09:28
0
for (; std::trunc(f) != f; f *= 10);
std::intmax_t const i(f);

Note, that there may still be UB as the range of floats is very large and you obviously need a signed integral type. Note that floats are usually not decimal.

user1095108
  • 14,119
  • 9
  • 58
  • 116