abs function return other value

Hi
Can somebody explain, why this peace of code

Difference=Accd-Accp;
Serial.print("Calculate differnce    ");
Serial.println(Difference);
delay(10000);
DeLta=abs(Difference);

Serial.print("abs mod DeLta        ");
Serial.println(DeLta);

give such a results - it doesn't change sign, but change value of variable?
May be I improperly use of abs() ?

Thanks
(the sceenshot and full text of program attached)

PulseDetector.ino (8.34 KB)

abs.png

Pro tip one, press Ctrl+T in the IDE. Your indentation is all over the place! And wHat Is iT wItH Your VarIaBlE NaMEs?

But I don't sport weird use of abs(). So why do you suspect it changes anything?

PS Russian? in a print doesn't work. Stick to ASCII :slight_smile:

Given that 71876 - 6340 = 65536... I'd bet my hat that you have some overflow going on somewhere. That is, some unsigned 16 bit variable is storing the result of the subtraction... Or this is one big coincidence!

I see that Differerence is of type long, so who knows, but there's something fishy there with that 65536.

Cosme_Fulanito:
Given that 71876 - 6340 = 65536... I'd bet my hat that you have some overflow going on somewhere. That is, some unsigned 16 bit variable is storing the result of the subtraction... Or this is one big coincidence!

I see that Differerence is of type long, so who knows, but there's something fishy there with that 65536.

If variable DeLta was int type, I can understand it. It will be mean, that it can contain value 32000, so 71000/32000=2 and 6340 is the remainder of the division. But as long type can contain 2000000 or so, i cant find by myself where is my error in the code.

When faced with such situations the correct course is to question your assumptions. You assume abs cannot fail. Let's test that assumption...

Change this...

DeLta=abs(Difference);

...to this...

if ( Difference < 0 )
{
  DeLta = -Difference;
}
else
{
  DeLta = Difference;
}

septillion:
wHat Is iT wItH Your VarIaBlE NaMEs?

Are u mean, that some names are restricted or what?

But I don't sport weird use of abs(). So why do you suspect it changes anything?

Sure, u r right.
So, what is the right way?

Remove #include <SoftwareSerial.h>, you are not using it.
That will also fix abs().

Explanation:

end of SoftwareSerial.h:

// Arduino 0012 workaround
#undef int
#undef char
#undef long
#undef byte
#undef float
#undef abs
#undef round

This will undefine the abs() macro defined in <Arduino.h>:

// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
...
#define abs(x) ((x)>0?(x):-(x))

and you get the <stdlib.h> abs() function:

/** The abs() function computes the absolute value of the integer \c i.
   \note The abs() and labs() functions are builtins of gcc.
*/
extern int abs(int __i) __ATTR_CONST__;
#ifndef __DOXYGEN__
#define abs(__i) __builtin_abs(__i)
#endif

oqibidipo:
Remove #include <SoftwareSerial.h>, you are not using it.

I supposed, that it need for Serial Monitor work.

anton1o:
I supposed, that it need for Serial Monitor work.

Have you ever seen a (pure) Serial.print example that includes SoftwareSerial :wink:

oqibidipo:
Remove #include <SoftwareSerial.h>, you are not using it.
That will also fix abs().

Explanation:

end of SoftwareSerial.h:

// Arduino 0012 workaround

#undef int
#undef char
#undef long
#undef byte
#undef float
#undef abs
#undef round




This will undefine the abs() macro defined in <Arduino.h>:


// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
...
#define abs(x) ((x)>0?(x):-(x))




and you get the <stdlib.h> abs() *function*:


/** The abs() function computes the absolute value of the integer \c i.
  \note The abs() and labs() functions are builtins of gcc.
*/
extern int abs(int __i) ATTR_CONST;
#ifndef DOXYGEN
#define abs(__i) __builtin_abs(__i)
#endif

Wow, that is quite ridiculous. Any idea what this whole workaround was for?

@anton1o, this might be the cleanest solution if you have a need for SoftwareSerial and abs

#include <SoftwareSerial.h>

// if abs() is not defined, define it
#ifndef abs
#define abs(x) ((x)>0?(x):-(x))
#endif

sterretje:
@anton1o, this might be the cleanest solution if you have a need for SoftwareSerial and abs

Or just use labs (the absolute value function which is meant to be used with long integers). :wink:

Did not know about that one. More studying to do :wink:

anton1o:
Are u mean, that some names are restricted or what?

Some names are indeed restricted (try declaring a variable setup for example) but I was more talking about a human standpoint. C(++) is a higher level programing language to make programming for us, humans, easy and understandable. bUt yOUr nOt reaLly HelPinG iF yOu typE lIke ThIs...

An accepted standard is to camelCaseVariableNames, ALL_CAPS_FOR_MACROS and UpperCamelCaseForConstVariables. These are easy to read names. Combine that with the fact a variable name should tell you exactly what it is you get easy to read code. In the long run (because others and future you can read it quick) it's easier to use longer but explaining variable names. So not InC but IncomingCallPin etc.

@oqibidipo, holy crap, that's ugly!

Thanks all, guys.
almost all works now.

Just i find one more problem -

can't to divide 23000/308000 - it gives me zero, while must be 0.075=0.08

While dividing 308000/23000 gives 13.00 (same not right, but near true) and must be 13.4

Can somebody explain, what is wrong here? I think that it cut mantiss, while there are 2 digits in number.

I used variable type "long" and for result "float" (this is AT328 )
Here the peace of code, the whole code and monitor print of the result of the calculations in attachment below.

if ( Difference < 0 )
  {
    DeLta = -Difference;
  }
  else
  {
    DeLta = Difference;
  }
  Serial.print("abs mod DeLta ");
  Serial.println(DeLta);
  Serial.println("Calculate %%%%%%%%%%%");
  DeLtaF = DeLta / Accd;
  Serial.print("DeLtaF      ");//
  Serial.println(DeLtaF);
  Serial.print("DeLtaF check operation 308000/23000 ");//
  DeLtaF = 308000 / 23000;                                                                                                                                                ;
  Serial.println(DeLtaF);
  Serial.print("DeLtaF check operation 23000/308000 ");//
  DeLtaF = 23000 / 308000;                                                                                                                                                ;
  Serial.println(DeLtaF);
  Serial.print("ModuLoF ");//
  ModuLoF = DeLta % Accd;
  Serial.println(ModuLoF);
  Serial.print("ModuLoF check operation 308000/23000 ");//
  ModuLoF = 308000 / 23000;                                                                                                                                                ;
  Serial.println(ModuLoF);
  Serial.print("ModuLoF check operation 23000/308000  ");//
  ModuLoF = 23000 / 308000;                                                                                                                                                ;
  Serial.print(ModuLoF);
  Serial.println("%  ");//

Any help would be apprpopriated.

PulseDetector.ino (9.68 KB)

not divide.png

If you want a float, do float math :wink: But I complemented you on using an int, don't mess it up now :stuck_out_tongue:

Keep in mind, that float math is slow and for large numbers NOT precise. (6 digits of significance max). So if you just want 1 decimal place just do 308000/2300 and imagine there to be a decimal point :wink:

Alright, you need to round... (308000 + 1150) / 2300 = (308000 + 2300/2) / 2300 Still faster then float and will work with numbers with more then 6 digits of significance. 308000 is right at the limit.

I just add to constant 2 digits, 23000.00 and constant start divide properly. 13.39 and 0.07

But in spite of I declare variables as "float", they are same don't divide properly.

float DeLta;
  float Difference;
  Difference = Accd - Accp;
  Serial.print("Calculate differnce    ");
  Serial.println(Difference);
  delay(10000);
  //DeLta=abs(Difference); this is return remain of dividing by 32k
  if ( Difference < 0 )
  {
    DeLta = -Difference;
  }
  else
  {
    DeLta = Difference;
  }
            //just try floating for keep divide result
  Serial.print("abs mod DeLta ");
  Serial.println(DeLta);
  Serial.println("Calculate %%%%%%%%%%%");
  float Accd;
  DeLtaF = DeLta / Accd;
  Serial.print("DeLtaF      ");//
  Serial.println(DeLtaF);
  Serial.print("DeLtaF check operation 308000/23000 ");//
  DeLtaF = 308000.00 / 23000.00;                                                                                                                                                ;
  Serial.println(DeLtaF);
  Serial.print("DeLtaF check operation 23000/308000 ");//
  DeLtaF = 23000.00 / 308000.00;                                                                                                                                                ;
  Serial.println(DeLtaF);
  Serial.print("ModuLoF ");//
  //ModuLoF = DeLtaF % Accd;
  Serial.println(ModuLoF);
  Serial.print("ModuLoF check operation 308000/23000 ");//
  ModuLoF = 308000.00 / 23000.00;                                                                                                                                                ;
  Serial.println(ModuLoF);
  Serial.print("ModuLoF check operation 23000/308000  ");//
  ModuLoF = 23000.000 / 308000.00;                                                                                                                                                ;
  Serial.print(ModuLoF);
  Serial.println("%  ");//

add later - I understand what the trick - if both variables are float it not work in mine sketch.
Just enough one of 2 operands will be float, another can be "int" or " long"
The result DelTaF = 8% that is almost true (real is 7.4%) (SEE MONITOR PRINT "DIVIDE VARIABLES""

Thanks, guys, for help so match.

divide variables.png