Reputation: 5989
I'm running time-consuming algorithm with bare-metal program(no OS) on our board using a processor(sparc architecture) developed in our team, and using gcc elf toolchain. With soft-float, it works fine, and I get the desired result after more than an hour(it's purely software run, it'll be much shortened with later special hardware). But using hard-float, I can do it in 15 minuites, good result. OK, but in some configuration of hard-float case, I see the exp() function is not working correctly. This case is where I want to print float correctly.
I have wrote a test code to test exp() function,
ab_printf("------- exp test--------\n");
float a[5] = {-0.438984, -0.357934, 0.174203, 0.280720, 0.372380};
for(i=0;i<5;i++){
ab_printf("x = %f, y = %f\n", a[i], 1./(1.+exp(-1.*a[i])));
}
ab_printf("------- end of exp test--------\n");
When I use soft float (with -msoft-float in Makefile), I get the correct result.
------- exp test--------
x = -0.438984, y = 0.391983
x = -0.357934, y = 0.411460
x = 0.174203, y = 0.543441
x = 0.280720, y = 0.569723
x = 0.372380, y = 0.592034
------- end of exp test--------
Then, I switch to hard float(using hardware FPU, = remove -msoft-float to generate hardware float instructions), but I understand exp() function is implemented by the toolset using software. (there is no exp instruction in the CPU. so the tool chain library will use Taylor expansion or something..). I use two libraries as below for linker when using hard-float.
LIBS += -L/opt/abde/lib/gcc/sparc-ab-elf/4.6.2/soft/v8 # line 1
LIBS += -L/opt/abde/sparc-ab-elf/lib/soft/v8 # line 2
If I use v8 instead of soft/v8 in line 1, program stops when printing float number so that's not an option. I suspect my tool-set has not built correctly, but I cannot build it in my system right now.
If I use v8 instead of soft/v8 in line 2, I see garbled data for float number. But I know I can get good detection result in this setup, though I see some small float errors build up as processing goes on, and I know in this setup exp() function also works anyway (thus the final correct result after 15 minutes).
When in hard-float mode, when I run from i = 0, it gives me this result(only the first one worked correct) :
------- exp test--------
x = -0.438984, y = 0.391983
x = -0.357934, y = 1.000000
x = 0.174203, y = 1.000000
x = 0.280720, y = 1.000000
x = 0.372380, y = 1.000000
------- end of exp test--------
when I run it from I = 1, it gives me (also, only first one correct)
------- exp test--------
x = -0.357934, y = 0.411460
x = 0.174203, y = 1.000000
x = 0.280720, y = 1.000000
x = 0.372380, y = 1.000000
------- end of exp test--------
What case would this be? The problem is I cannot build the tool-chain right now on my system.
Upvotes: 1
Views: 131
Reputation: 5989
It looks like it has problem with float printing usinb ab_printf. I found other platform has another problem printing float. (https://github.com/esp8266/Arduino/issues/341). So I chose to use this setup :
LIBS += -L/opt/abde/lib/gcc/sparc-ab-elf/4.6.2/soft/v8 # line 1
LIBS += -L/opt/abde/sparc-ab-elf/lib/v8 # line 2
This setup lets me to use hard-float with no problem other than float printf. SO to print float value I decided to do away with doing like (int)(1./(1.+exp(-1.*a[i])) * 10000.) and use decimal integer print. Hope someone could come with another good solution.
Upvotes: 0
Reputation: 67855
Make the program to work with floats not the double values. If you use literal like 1.0 it is double. Use 1.0f instead. exp takes double parameter and returns double.
1.+exp(-1.*a[i]) will convert a[i] to double, then it does the double operations, and next converted again to single float. It has a quite important impact on the precision. I do not know what numbers (32 or 64 bit) your FPU uses. Make them all same as the FPU ones.
note that you have different exp functions depending on the float type (expf, exp, expl)
Upvotes: 0