Found a 64bit double implementation library, but I cannot compile it

Hi,
i found this 64 bit double implementation: 64 Bit float Emulator in C, IEEE754 compatibel - Mikrocontroller.net
i want try it so i've taken the avr_f64.c and avr_f64.h, imported in an arduino UNO sketch, changed all "static uint64_t interp" into "const uint64_t interp" into .c, and decommented the define of the function i'm using in the .h

now it compile, but the linker go crazy: it say it has "undefined reference to" with all function in the avr_f64. So i've checked the parameters during compile time:

avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o /tmp/build2804180871486054822.tmp/testDouble.cpp.elf /tmp/build2804180871486054822.tmp/avr_f64.c.o /tmp/build2804180871486054822.tmp/testDouble.cpp.o /tmp/build2804180871486054822.tmp/core.a -L/tmp/build2804180871486054822.tmp -lm

seems like everything is is ok (notice: /tmp/build2804180871486054822.tmp/avr_f64.c.o and -L/tmp/build2804180871486054822.tmp).

What is going wrong?

The C++ compiler performs name mangling to enable function overloading. The C compiler does not.

So, when the C++ code calls a function, the linker expects a name-mangled function to exist somewhere. The C compiler has not created one.

You need to add

extern "C" {

before and

}

after the function declarations in the header file so that the linker knows that the functions named in the file are not to be name mangled in the C++ code.

thank, i'd never though it was caused by c++ vs c :grin:

added

#ifdef __cplusplus
extern "C"{
#endif 

#ifdef __cplusplus
}
#endif

just one more question, why it doesn't work if i use extern without #ifdef __cplusplus??

why it doesn't work if i use extern without #ifdef __cplusplus??

Because the header file is used by both C and C++ code. Without the conditional statements, the header files can only be used by one language.

ughh that's confusing, fell like variables are duplicated in both language. well, i think i should learn how compiler handle c++ and multiple language mix

Have you allready done some measurements?

  • lib size
  • performance?

How does it compare to the Big Number library - Arduino Forum -

tested:

lib size: 17908byte (only using f_sin(), f_sd and f_to_string)
using all trigonometric set plus f_add, f_sub and f_mult is 24238 byte

this trigonometric formula using float execute in 1ms, with this lib 50ms.

but seems like sin is wrong, it doesn't give the right value.

The bignumber lib doesn't have the trig function i need (sin, cos, atan2)

ughh that's confusing

Not really. You are telling the c++ compiler that the code is to be compiled using C calling convention. The c compiler knows that. When the linker runs, all the code produced will link together nicely.

fell like variables are duplicated in both language.

No variables are duplicated.

i don't understand, if function name are declared with C convection, why is not the same for variable? why not all header should be putted as extern "C"?

why is not the same for variable?

Because C and C++ treat variables the same.

why not all header should be putted as extern "C"?

Because 99% of header files are used with just one language.

sorry i don't say all headers, but that the extern block should be possible to embrace all

The bignumber lib doesn't have the trig function i need (sin, cos, atan2)

The examples contain the sin() function and from that the cos() and atan2 can be derived

bignumber cos(x)
{
sin(x+PI/2);
}

atan2(y, x) is more complex :slight_smile: - check wikipedia for the formula

i know i can derive them from just one, but i haven't seen the sin(), i'll look closer tomorrow

#include <BigNumber.h>

BigNumber pi;
const byte precision = 20;

// function to display a big number and free it afterwards
void printBignum (BigNumber n)
{
  char * s = n.toString ();
  Serial.print (s);
  free (s);
}  // end of printBignum

BigNumber sine (BigNumber x, BigNumber p)
  {
   BigNumber one = 1;
   BigNumber two = 2;
   BigNumber val = one;
   
   while (p > 0)
     {
     val = one - val * x * x / (two * p) / (two * p + one);
     p = p - one;
     }
   val = x * val;
   return val;
  } // end of sine

BigNumber cosine (BigNumber x, BigNumber p)
  {
  BigNumber sin = sine (x, p);
  BigNumber sinSquared = sin * sin;
  BigNumber oneMinusSine = BigNumber (1) - sinSquared;
  return  oneMinusSine.sqrt ();
  }  // end of cosine
  
BigNumber tangent (BigNumber x, BigNumber p)
  {
  return (sine (x, p) / cosine (x, p));
  } // end of tangent

void setup ()
  {
  BigNumber::begin ();  // initialize library
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");

  Serial.begin (115200);
  Serial.println ();
  Serial.println ("Starting ...");
  
  BigNumber::setScale (20);
  
  for (BigNumber foo = "0.1"; foo <= pi / BigNumber (2); foo += BigNumber ("0.1"))
    {
     Serial.print ("Sine of ");
     printBignum (foo); 
     Serial.print (" = ");
     printBignum (sine (foo, precision));
     Serial.println ();
    } // end of for

  for (BigNumber foo = "0.1"; foo <= pi / BigNumber (2); foo += BigNumber ("0.1"))
    {
     Serial.print ("Cosine of ");
     printBignum (foo); 
     Serial.print (" = ");
     printBignum (cosine (foo, precision));
     Serial.println ();
    } // end of for

 for (BigNumber foo = "0.1"; foo < pi / BigNumber (2); foo += BigNumber ("0.1"))
    {
     Serial.print ("Tangent of ");
     printBignum (foo); 
     Serial.print (" = ");
     printBignum (tangent (foo, precision));
     Serial.println ();
    } // end of for

  } // end of setup
  
 void loop () {}

Output:

Starting ...
Sine of 0.1 = 0.09983341664682815230
Sine of 0.20000000000000000000 = 0.19866933079506121546
Sine of 0.30000000000000000000 = 0.29552020666133957510
Sine of 0.40000000000000000000 = 0.38941834230865049166
Sine of 0.50000000000000000000 = 0.47942553860420300027
Sine of 0.60000000000000000000 = 0.56464247339503535720
Sine of 0.70000000000000000000 = 0.64421768723769105367
Sine of 0.80000000000000000000 = 0.71735609089952276163
Sine of 0.90000000000000000000 = 0.78332690962748338846
Sine of 1.00000000000000000000 = 0.84147098480789650666
Sine of 1.10000000000000000000 = 0.89120736006143533995
Sine of 1.20000000000000000000 = 0.93203908596722634967
Sine of 1.30000000000000000000 = 0.96355818541719296470
Sine of 1.40000000000000000000 = 0.98544972998846018066
Sine of 1.50000000000000000000 = 0.99749498660405443095
Cosine of 0.1 = 0.99500416527802576609
Cosine of 0.20000000000000000000 = 0.98006657784124163112
Cosine of 0.30000000000000000000 = 0.95533648912560601964
Cosine of 0.40000000000000000000 = 0.92106099400288508280
Cosine of 0.50000000000000000000 = 0.87758256189037271612
Cosine of 0.60000000000000000000 = 0.82533561490967829724
Cosine of 0.70000000000000000000 = 0.76484218728448842626
Cosine of 0.80000000000000000000 = 0.69670670934716542092
Cosine of 0.90000000000000000000 = 0.62160996827066445649
Cosine of 1.00000000000000000000 = 0.54030230586813971739
Cosine of 1.10000000000000000000 = 0.45359612142557738778
Cosine of 1.20000000000000000000 = 0.36235775447667357764
Cosine of 1.30000000000000000000 = 0.26749882862458740701
Cosine of 1.40000000000000000000 = 0.16996714290024093862
Cosine of 1.50000000000000000000 = 0.07073720166770290998
Tangent of 0.1 = 0.10033467208545054505
Tangent of 0.20000000000000000000 = 0.20271003550867248332
Tangent of 0.30000000000000000000 = 0.30933624960962323303
Tangent of 0.40000000000000000000 = 0.42279321873816176197
Tangent of 0.50000000000000000000 = 0.54630248984379051324
Tangent of 0.60000000000000000000 = 0.68413680834169231707
Tangent of 0.70000000000000000000 = 0.84228838046307944812
Tangent of 0.80000000000000000000 = 1.02963855705036401275
Tangent of 0.90000000000000000000 = 1.26015821755033913712
Tangent of 1.00000000000000000000 = 1.55740772465490223055
Tangent of 1.10000000000000000000 = 1.96475965724865195088
Tangent of 1.20000000000000000000 = 2.57215162212631893539
Tangent of 1.30000000000000000000 = 3.60210244796797815106
Tangent of 1.40000000000000000000 = 5.79788371548288964359

Still an amazing lib :slight_smile:

directly derive cosine from sine uses less steps: cosine(x) = sine(x+PI/2); so might be faster?

however it uses a big constant so thats worse for the footprint.

#include "BigNumber.h"

void setup(){
  Serial.begin(115200);
  delay(2000);
  BigNumber::begin ();
  BigNumber::setScale (20);
}

int i=1;
unsigned long time;
void loop()
{
  Serial.println( i );
  
  Serial.print( sin(i) );
  Serial.print(" ");
  printBignum( sine( i, precision ) );
  Serial.println();
  
  Serial.print( cos(i) );
  Serial.print(" ");
  printBignum( cosine( i, precision ) );
  Serial.println();
  Serial.println();
  delay(1000);
  i++;
}

// function to display a big number and free it afterwards
void printBignum (BigNumber n)
{
  char * s = n.toString ();
  Serial.print (s);
  free (s);
}  // end of printBignum

work until -15 <= i <= 15…

using a precision of 10 the range is -7 <= i <= 7

i tryed to change
while (p > 0)

into

while (p > 0.00001)

but nothing to do. I’m having some problem with my ADSL, so it’s pretty hard to find alternative algorithm, i hope my adsl will feel better tomorrow :grin:

robtillaart:
directly derive cosine from sine uses less steps: cosine(x) = sine(x+PI/2); so might be faster?

You are right, but I couldn't get that to work yesterday. But this is why:

  BigNumber::begin ();  // initialize library
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
...  
  BigNumber::setScale (20);

Should have been:

  BigNumber::begin ();  // initialize library
  BigNumber::setScale (20);
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
...

It thought pi was 3.

Now cosine can be:

BigNumber cosine (BigNumber x, BigNumber p)
{
   return sine (x + pi / BigNumber (2), p);
}  // end of cosine

lesto:
work until -15 <= i <= 15…

Yes but these are radians, not degrees. You shouldn’t have to work outside the range 0 to 2 * pi. After that it just repeats.

Or even the range 0 to pi/2. You just need to force your numbers into that range and swap the sign if necessary.

I understand, now I'll try again.

Make sure you move the definition of pi to be after where it sets the scale, as I discussed above.