Float math using only variables, how to define decimal places?

Here is what I am trying to do

int z = pulseIn(2, HIGH);
int y = pulseIn(2, LOW);
int x = z + y;

float w = z / x;
int v = w * 4000;

I am expecting an integer output for v: Percentage w% * 4000 = 0 to 4000. What am I missing here?

Thats right: v is an integer (+/- 32000+) ......... use float for x,y and z (solves problem) w will also always be an integer (int/int = int)

What am I missing here?

An explanation of what the problem is.

knut_ny: Thats right: v is an integer (+/- 32000+) ......... use float for x,y and z (solves problem) w will also always be an integer (int/int = int)

Okay I walked through the door after you pointed to it, thank you sir!

float z = pulseIn(2, HIGH);
float y = pulseIn(2, LOW);
float x = z + y;

float w = z / x;
int v = w * 4000;

You could also fix it by casting z or x to a float in the first case.

KeithRB: You could also fix it by casting z or x to a float in the first case.

Copy that:

int z = pulseIn(cell, HIGH);
  int y = pulseIn(cell, LOW);
  float x = z + y;
  
  float w = z / x;
  int v = w * 4000;
unsigned long z = pulseIn(2, HIGH);
unsigned long y = pulseIn(2, LOW);
unsigned long x = z + y;

float w = (float) z / (float) x;  // although why?
int v = w * 4000;

// why not
int v = (int) ( 4000UL * z / x ); // it does the math in 32 bit unsigned THEN casts the result to signed 16 bit.

I am expecting an integer output for v: Percentage w% * 4000 = 0 to 4000. What am I missing here?

One answer is variable types and casting.

Also AVR has no FPU and only has 32 bit floats whereas Arduino supports 64 bit integers good to 19 places and can do those faster than floats good to 6 places, here’s the missing:

the decimal point is just part of the representation. If I want to keep meters to 3 places accuracy then I make my unit micrometers (3 places beyond accuracy to divide into without rounding loss) and work in 32 or 64 bits. The value stored is meters x 1,000,000 but I stick a decimal point in at millions and only show the next 3 digits when printing to 3 places.
Integer divide ( / ) and remainder ( % ) operations let you split integers on a decimal place. You print the higher order value first then a decimal place then pad in zeros as needed (for 3 places: if < 100; if < 10 ) before printing any remainder.
You could use sprintf() but that includes a lot of code and a buffer. And format string specifiers.

Sounds like a case for muldiv (a, b, c) - anyone who’s au-fait with AVR assembler
could probably knock one up…

Failing that map can be used, something like this (untested).

// return a*b/c using enough precision in intermediate results
int muldiv (int a, int b, int c)
{
  return map (a, 0, c, 0, b) ;
}

MarkT: Sounds like a case for muldiv (a, b, c) - anyone who's au-fait with AVR assembler could probably knock one up...

The Forth word is */, the scaling operator. It takes 2 ints and multiplies them into a long then divides that by a 3rd int to leave a scaled int.

GoForSmoke: // why not int v = (int) ( 4000UL * z / x ); // it does the math in 32 bit unsigned THEN casts the result to signed 16 bit.

One answer is variable types and casting.

Also AVR has no FPU and only has 32 bit floats whereas Arduino supports 64 bit integers good to 19 places and can do those faster than floats good to 6 places, here's the missing:

I have much to learn, can you please verify my assumptions of what just happened?

Referring to: int v = (int) ( 4000UL * z / x ) "int v" declared an integer variable as usual "(int)" requested int output? "(4000UL * z / x)" the operation in the parentheses uses more math friendly 32-bit stuff; the #UL just declares that 4000 as an unsigned long

Steelmesh:

GoForSmoke: // why not int v = (int) ( 4000UL * z / x ); // it does the math in 32 bit unsigned THEN casts the result to signed 16 bit.

One answer is variable types and casting.

Also AVR has no FPU and only has 32 bit floats whereas Arduino supports 64 bit integers good to 19 places and can do those faster than floats good to 6 places, here's the missing:

I have much to learn, can you please verify my assumptions of what just happened?

Referring to: int v = (int) ( 4000UL * z / x ) "int v" declared an integer variable as usual "(int)" requested int output? "(4000UL * z / x)" the operation in the parentheses uses more math friendly 32-bit stuff; the #UL just declares that 4000 as an unsigned long

(int) casts the output to type int to fit v, otherwise v would get the 16 wrong bits of a 32 bit result. This is assuming that v is percent as in 0 to 100 or could it be 1000 or more %?

The L means use a 32 bit integer and the letter U means code it to use rollover-friendly unsigned math. Not "just".