Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Illegal float values

Tags:

c

exception

gcc

I am currently working on an embedded microcontroller and use a custom printf routine. The toolchain is the GCC Toolchain for the AVR32 architecture.

I have the problem that upon calling vsnprintf or similar for the second time that the CPU enters an exception condition.

From support, I received the answer that:

We could not find any obvious reason for such behavior. However, creating a float overflow condition by writing byte by byte is not safe. We cannot ensure the value generated by this and it is recommended to check using “FLT_MAX”.

Now I am wondering: What are "illegal" float values? Shouldn't all bit combinations represent at least some value? If relevant: sizeof(float) is 4 bytes.

like image 417
Tom L. Avatar asked Dec 09 '13 11:12

Tom L.


2 Answers

Summary

I suggest you print the bits of floating-point values as if they were a hexadecimal integer, as shown in code below, so that you can analyze those bits to see if they contain the values you are attempting to compute or have been modified improperly due to some bug.

Details

The AVR32CU Technical Reference Manual says “The floating point hardware conforms to the requirements of the C standard, which is based on the IEEE 754 floating point standard.“ The latter clause is false; the C standard is not based on IEEE 754. The C standard does specify bindings to IEEE 754 (via the name IEC 60559) as an optional feature of C implementations. I will presume that the model of AVR32 CPU you are using conforms to IEEE 754 to some degree.

There are no “illegal” values in IEEE 754. There are values that do not represent numbers, and some of those values are intended to cause exceptions. Such a value is called a NaN (for “Not a Number”). There are quiet NaNs and signaling NaNs. Quiet NaNs are intended to pass through operations silently, producing a NaN result. E.g., 3 + NaN should produce NaN. Signaling NaNs are intended to cause exceptions, which may cause changes to program control (such as signals or program aborts).

The technical reference manual cited above also says “Signalling NaN are not provided, all NaN are non-signalling (quiet).”

A good vsnprintf routine should accept quiet NaN values for printing and should format them by producing a string such as “NaN”. When a signaling NaN is passed for formatting, I suppose it might be reasonable either to format it or to produce an exception.

I expect the message you received from support is suggesting that your software created some kind of NaN, and that vsnprintf cannot handle these. From the phrasing, I think their response is speculative.

If you are creating floating-point values by assembling bytes, then you may have created a NaN when you did not intend to, if there was some error in your software. I suggest that you debug this by using vsnprintf to print the bytes of the floating-point value instead of printing it with a floating-point format specifier.

If the GCC version you are using has the usual features of GCC, and the unsigned int in your implementation is 32 bits, you can format the bits of a 32-bit float value x as a hexadecimal value using:

vsnprintf(Buffer, BufferLength, "0x%x",
    (union { float f; unsigned int u; }) {x} .u);

The second line uses a compound literal to put the value x into a union and reinterpret its bytes as an unsigned int. (This is a supported way in C to reinterpret the bytes of an object. Many people use pointer aliasing, which works in GCC if the appropriate flag is used, but it is not generally supported by the C standard. Another supported method is to copy the bytes, as with unsigned int u; memcpy(&u, &x, sizeof u);.)

Once you see what the bits in the float are, you can interpret them manually from information in the IEEE 754 standard or using an online analyzer. (Select the “hexadecimal” button to input hexadecimal values to be interpreted.)

In an IEEE-754 32-bit binary floating-point object, the value is a NaN if:

  • Bits 31 has any value. (It is the sign bit, irrelevant for recognizing a NaN.)
  • Bits 30 to 23 are all ones.
  • Bits 22 to 0 are not all zeros.

(If Bits 30 to 23 are all ones but bits 22 to 0 are all zeroes, the value is an infinity. This is not illegal but might also cause a low-quality vsnprintf to generate an exception.)

like image 173
Eric Postpischil Avatar answered Sep 24 '22 11:09

Eric Postpischil


i didnt work on AVR32, but 'illegal' float values, generally float (single-precision arithmetic) is important topic in numeric methods. Maximal number for float is:

FLT_MAX = 3.40282e+38

but float have also limit for floating values. The closer to zero you are, more floating digits you can specify.

float

for example:

the minimal value between [1,2] is 1.19209e-07 ( it is 2^-23) also known as macheps (machine epsilon ( FLT_EPSILON from float.h ))

the minimal value between [2,4] is 2 * 1.19209e-07 = 2 * 2^-23 it also works for the oder side: the minimal value between [1/2,1] is 2^-24.

why this is happening? Let define number as beforedot.afterdot.

the larger number is, more bits is required to write beforedot number, and simetric for less numbers.

In conclusion:

Min for float: 1.0842e-19,

Max for float: 3.40282e+38.

like image 30
Paul Dew Avatar answered Sep 21 '22 11:09

Paul Dew