Extract integers from a float?

I have floating point numbers with two decimal places, like 23.46. I want to extract two integers, in this case 23 and 5. The 5 is the result of rounding up the 0.46 to 0.5 and converting it to an integer. The following sketch works but is there a neater way to do it? Lot of code for what seems a trivial task?

float full = 23.46;
int integerPart; // Need result of 23
float decimalPart; // But need 5, not 5.0 etc.

void setup()
{
  Serial.begin(115200);
  delay(200);
  Serial.println("Sketch = ExtractTwoIntegersFrom2DPFloat");
  integerPart = (int) full;
  Serial.print("integerPart = ");
  Serial.println(integerPart);

  decimalPart = full - integerPart;
  // Round two decimals to one by adding 0.05 & truncating
  decimalPart = decimalPart + .05;
  // But to get int needed, had to introduce another variable
  int decimalPartAsInt = 10 * decimalPart;
  Serial.print("decimalPartAsInt = ");
  Serial.println(decimalPartAsInt);
}

void loop()
{
}

You take the integral part like you already do
You subtract this integral part from the float, what is left behind the decimal you multiply by 10 for example + 0.5 and you take the integral part again (if you want a single rounded decimal digit)

Have you tried using abs()

1 Like

abs() takes an integer value - so doesn't help here.

'modf()' is the answer:

https://cplusplus.com/reference/cmath/modf/

1 Like

modf() will return floats; the results will still need to be cast to int

float full_float
float integerPart_float

int integerPart
int fractionPart

fractionPart = modf( full_float, &integerPart_float );
integerPart  = integerPart_float;
1 Like

That will be 0 … need to multiply by 10 and add 0.5 before converting it into the int

Édit see below

that is the integer part, surely - the bit that is >0 ? :thinking:

Sorry I meant that for the fractional part.
Mistyped it
(Can be negative or zero too though not > 0)

Ah, yes - you are right there! :+1:

I think you can add one then cast the float to an int. Let me know if that works.

Thanks, looks good. Will study the reference you gave later as modf() does indeed seem to be exactly what I need. But meanwhile my code reports:

cannot convert 'float*' to 'double*' for argument '2' to 'double modf(double, double*)'

What have I got wrong here?

float full_float = 23.46;
float integerPart_float;

int integerPart;
int fractionPart;

void setup()
{
  Serial.begin(115200);
  delay(200);

  fractionPart = modf( full_float, &integerPart_float );
  integerPart  = integerPart_float;

  Serial.print("integerPart = ");
  Serial.println(integerPart);
  Serial.print("fractionPart = ");
  Serial.println(fractionPart);
}

void loop()
{
}

The easy fix is to Make them double instead of float

Note that your fraction part needs some massaging as well as explained above

1 Like

No, it doesn't!

Nope…

Say you have 42.10
Adding one will be 43.10…

I'm not sure I follow you. Surely I already did the 'massaging' in my original code?

I meant


double full_float = 23.46;
double integerPart_float;

long integerPart;
long fractionPart;

void setup()
{
  Serial.begin(115200);
  delay(200);

  fractionPart = modf( full_float, &integerPart_float ) * 10.0 + 0.5;
  integerPart  = integerPart_float;

  Serial.print("integerPart = ");
  Serial.println(integerPart);
  Serial.print("fractionPart = ");
  Serial.println(fractionPart);
}

void loop()
{
}

1 Like

That does the job, thanks to both you and @awneil.
Now I need to understand it!
And surprisingly it has hardly any fewer lines of code in total than my original?

In my Macro Express Pro app there's a 'Split String' command and I was wondering if there was an Arduino/C equivalent? I suppose modf() is close?.

Manipulating mixtures of different types of variable is an aspect I'm finding hard work!
:slightly_smiling_face:

You don’t have a String to begin with but if really really you want to use Strings you could

float f = 43.21;
String f_s = String(f, 1); // as a String with one decimal digit

Then you can find the dot using indexOf() and extract subString for what’s before and after the dot then use toInt() to transform the subStrings back into numbers

See the string class API

(We would of course not recommend this at all, big waste of SRAM and CPU cycles)

But most of those lines of code are just "framework" - declaring the variables, printing the results, etc.

The actual "work" has gone from 3 lines to 2 - a 33% saving.

Counting "lines of code" is generally not a terribly useful indication of the efficiency of high-level language code ...