define a float

Hello,

I am all new to Arduino and C++ and trying to learn/understand it. It was 25+ years ago I did some programming in a non high level scripting language. Only playing with Python for the last 10 years.

So I have been reading up on the difference between #define and const on the forum.
For exampel these two questions:
The difference between #define and const
#define versus const and other software performance issues

My first Arduino project is building some sensors with the MySensors project. And now I am trying to improve the battery measuring code.

So to my question:

To make the source code more readable and to follow what seems to be the standard way if writing code in this project a decided to go with #define on the user adjustable pre compiling "variables". But I havetrouble with the floats.

This is a code working:

#define R1 984000.
#define R2 472000.
const float batFact = ((1.1/1023)*((R1+R2)/R2));

Gives batFact = 0.00331693 which is correct.

This code is not working:

#define R1 984000
#define R2 472000
const float batFact = ((1.1/1023)*((R1+R2)/R2));

Gives batFact = 0.00322581 which is incorrect.

As I understand it, it must because the pre-compiler doesn't understand that R1 and R2 is not an integer. But by adding the decimal point it does.

Now I wonder is there any way to tell the compiler that R1 and R2 is a float without the ending decimal point?
I have tried static_cast((1.1/1023)*((R1+R2)/R2)) which make no difference.

The reason for searching for a different way to get this working is that I can see how easy it will be to forget to add the decimal point.

when you using #define keyword, you tell the compiler that your "thing" is a macro. What that means is that whenever the compiler see your "thing", it will replace it with the value. Thus your "thing" is not a variable, so it does not have a type.

in

const float batFact = ((1.1/1023)*((R1+R2)/R2));
batFact = 0.00322581

you define batFact as a const but then attempt to assign a value to it - it would give a error assignment of read-only variable 'batFact'

arduino_new:
when you using #define keyword, you tell the compiler that your "thing" is a macro. What that means is that whenever the compiler see your "thing", it will replace it with the value. Thus your "thing" is not a variable, so it does not have a type.

Yes I do understand that.

Therefore I wonder if there is any way around to make the formula for batFact to calculate the correct answer without the decimal point in the two #define

you could cast one of the integers (r1 or R2) to a float, e.g.

  #define R1 984000
#define R2 472000
const float batFact = ((1.1/1023)*(((float)R1+R2)/R2));

horace:
in

const float batFact = ((1.1/1023)*((R1+R2)/R2));

batFact = 0.00322581



you define batFact as a const but then attempt to assign a value to it - it would give a error *assignment of read-only variable 'batFact'*

I have updated the question. I am not trying to set the batFact variable. That line in the question was to show the result of the calculation. I see that it was confusing.

Sorry for that.

strixx:
Yes I do understand that.

Therefore I wonder if there is any way around to make the formula for batFact to calculate the correct answer without the decimal point in the two #define

Yes you could. But you must explicitly cast them to a float like this:

const float batFact = ((1.1/1023)*(((float)R1+(float)R2)/(float)R2));

There is no need to cast all them (R1, R2, R3) as floats. It is just enough to cast one of them.

 #define R1 984000
#define R2 472000

void setup() 
{
  Serial.begin(9600);
 
  const float batFact = ((1.1/1023)*(((float)R1+R2)/R2));

  Serial.print(batFact, 6);  //prints: 0.003317 float is binary32 formatted data which gives accuracy to 6-7 digits.

}

void loop() 
{
 
}

This is typical one of the problems of #define that const solves

try

const float R1 = 984000;
const float R2 = 472000;

no decimal point needed and the compiler gets the type information it needs.

GolamMostafa:
There is no need to cast all them (R1, R2, R3) as floats. It is just enough to cast one of them.

 #define R1 984000

#define R2 472000

void setup()
{
  Serial.begin(9600);

const float batFact = ((1.1/1023)*(((float)R1+R2)/R2));

Serial.print(batFact, 6);  //prints: 0.003317 float is binary32 formatted data which gives accuracy to 6-7 digits.

}

void loop()
{

}

Thanks! As I wrote I am trying to learn/understand, not just do.
So I have to follow up with two questions:

Why is that working?
1.1/1023 is calculated correctly because there is a float in the operation, right?
Why is not ((1.1/1023)((R+R2)/R2))working, when ((1.1/1023)(((float)R1+R2)/R2)) is?
Is it because of the parentheses? And that it calculates the (R1+R2)/R2 part first/separate and there is no float in that calculation?

And have I understood it correctly when I think that in the compiled code there will be only one value stored, and that is the sum of my formula? Which is calculated when compiled, and not by the Arduino at run time.

strixx:
Thanks! As I wrote I am trying to learn/understand, not just do.
So I have to follow up with two questions:

Why is that working?
1.1/1023 is calculated correctly because there is a float in the operation, right?
Why is not ((1.1/1023)((R+R2)/R2))working, when ((1.1/1023)(((float)R1+R2)/R2)) is?
Is it because of the parentheses? And that it calculates the (R1+R2)/R2 part first/separate and there is no float in that calculation?

And have I understood it correctly when I think that in the compiled code there will be only one value stored, and that is the sum of my formula? Which is calculated when compiled, and not by the Arduino at run time.

Because

(R+R2)/R2)

results to an int

but

(((float)R1+R2)/R2)

results to a float

strixx:
Which is calculated when compiled, and not by the Arduino at run time.

right.

The C++ way of doing what you are attempting is using constexpr functions... a function that will evaluate (literals) at compile time, like this:

#define R1 984000
#define R2 472000

constexpr float batFact(float a, float b)
{
  return ((1.1/1023)*((a+b)/b));
}

const float myValue = batFact(R1, R2);

void setup()
{
  Serial.begin(9600);
  Serial.println(myValue);
}

void loop() 
{
}

Why not

#define R1 (float)984000

The #define works like a simple text replacement; it does not have to be a valid expression on its own.

You can do stupid things like:

#define stupid (27
Serial.print(stupid));

...but please don't.

The const hint is the best way to do this for simple values. (See reply #8.)

1.1/1023 is calculated correctly because there is a float in the operation, right?

Not correct in any case. The correct divisor is 1024, as there are 1024 values that can arise.

Minor correction but nevertheless an important point.

jremington:
Not correct in any case. The correct divisor is 1024, as there are 1024 values that can arise.

may arise from what? it' a compile-time constant...

It arises from the fact that the ADC has 10 bits of resolution, leading to 1024 possible values.

jremington:
It arises from the fact that the ADC has 10 bits of resolution, leading to 1024 possible values.

well... 1023 values plus zero. in any case it is off topic.

The OP is interested in correct results, so it is not off topic to suggest using the correct constants.

strixx:
1.1/1023 is calculated correctly because there is a float in the operation, right?
Why is not ((1.1/1023)((R+R2)/R2))working, when ((1.1/1023)(((float)R1+R2)/R2)) is?
Is it because of the parentheses? And that it calculates the (R1+R2)/R2 part first/separate and there is no float in that calculation?

when you evaluate an expression you need to consider operator Precedence and Associativity, see

in the expression (R1+R2)/R2 the (R1+R2) is evaluated first (due to the ()) then the division
in the expression R1+R1/R2 the R1/R2 has the highest Precedence so it is evaluated first then the addition

you also need to consider conversion between types
http://www.cplusplus.com/doc/tutorial/typecasting/

for example why is the output of

#define R1 984000
#define R2 472000
Serial.println(R1/R2 + (float)R2, 8);
Serial.println((float)R1/R2 + R2, 8);

this

472002.00000000
472002.09375000

It arises from the fact that the ADC has 10 bits of resolution, leading to 1024 possible values.

With Vref = 1.1V

With Vin = 0V, ADC Value = 0x00 = 0
With Vin = 1.1V, ADC Value = 0x3F = 1023

So, when Vin = VDT, ADC Value = (1023/1.1)*VDT (Is it correct?)