1

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.

Chan Kim
  • 5,177
  • 12
  • 57
  • 112
  • One possibility is that something in the ab_printf processing is messing up the hardware floating point. To test that theory, you could store the results in an array in the loop, and only output them from a later loop. – Patricia Shanahan Jul 11 '17 at 11:09
  • it's a good guess, I tried that but it was not the case. Thanks! – Chan Kim Jul 11 '17 at 11:57
  • 1
    Do you get messed-up results for other `math.h` functions, like `sin`, `atan`, etc., or is the issue specific to `exp`? It would be good to eliminate `printf` issues from consideration, too, since the code converting a float to decimal for output may well be significantly more complicated than the code performing `exp`. – Mark Dickinson Jul 11 '17 at 12:06
  • @MarkDickinson sin() is also messed up. and I found if I do print with looping with `i`, it prints ok(I mean with explicit index of 0,1,2,3,.. it prints ok). WHen I print with loops, it's messed up. It looks like the ab_printf has a bug when printing float with loop. – Chan Kim Jul 11 '17 at 13:16
  • Do you have an optimizations enabled? If so, it may be worth testing with them turned off. – Patricia Shanahan Jul 11 '17 at 13:49
  • Band-aid. Since code can apparently print 1 `float`, call `ab_printf();` twice; `ab_printf("x = %f", a[i]); ab_printf(", y = %f\n", 1./(1.+exp(-1.*a[i])));` – chux - Reinstate Monica Jul 11 '17 at 15:28

2 Answers2

0

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)

0___________
  • 60,014
  • 4
  • 34
  • 74
  • I checked it's not related to float, double. If I print it without loop, using explicit index of 0,1,2,3,.. it prints them ok. It looks like ab_printf function has a problem when printing with float..in the loop. – Chan Kim Jul 11 '17 at 13:17
  • how did you check it? Have you made them float? – 0___________ Jul 11 '17 at 13:20
  • If I print like ab_printf("x = %f, y = %f\n", a[0], sin(a[0])); ab_printf("x = %f, y = %f\n", a[1], sin(a[1])); ab_printf("x = %f, y = %f\n", a[2], sin(a[2])); ab_printf("x = %f, y = %f\n", a[3], sin(a[3])); ab_printf("x = %f, y = %f\n", a[4], sin(a[4])); it prints ok, but if I use for(i=0;i<5;i++) ab_printf("x = %f, y = %f\n", a[i], sin(a[i])); it doesnt print it correctly, the values are wrong. So it's not float/double problem. – Chan Kim Jul 11 '17 at 14:35
0

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.

Chan Kim
  • 5,177
  • 12
  • 57
  • 112
  • Detail: `ab_printf("y = %f\n", 1./(1.+exp(-1.*a[i])));` --> it is _not_ printing a `float`, but a `double`. Perhaps the mis-behaving `ab_printf()` can handle printing a raw `float`? Try. `float F = 1./(1.+exp(-1.*a[i])); ab_printf("x = %f, y = %f\n", a[i], F);` – chux - Reinstate Monica Jul 11 '17 at 15:20