subnormal IEEE 754 floating point numbers support on iOS ARM devices (iPhone 4)

While porting an application from Linux x86 to iOS ARM (iPhone 4), I’ve discovered
a difference in behavior on floating point arithmetics and small values.

64bits floating point numbers (double) smaller than [+/-]2.2250738585072014E-308 are called denormal/denormalized/subnormal numbers in the IEEE 754-1985/IEEE 754-2008 standards.

  • How to tell Xcode how to include a library specified with angle brackets?
  • GCC on OS X allocs more memory than expected
  • linking and using a C++ library with an Objective-C application
  • How can I 'break away' from Cocoa and develop Mac OpenGL applications in C/C++?
  • Can I make clang generate absolute addresses for function pointers?
  • are 2^n exponent calculations really less efficient than bit-shifts?
  • On iPhone 4, such small numbers are treated as zero (0), while on x86, subnormal numbers can be used for computation.

    I wasn’t able to find any explanation regarding conformance to IEEE-754 standards on Apple’s documentation Mac OS X Manual Page For float(3).

    But thanks to some answers on Stack Overflow ( flush-to-zero behavior in floating-point arithmetic , Double vs float on the iPhone ), I have found some clues.

    According to some searches, it seems the VFP (or NEON) math coprocessor used along the ARM core is using Flush-To-Zero (FTZ) mode (e.g. subnormal values are converted to 0 at the output) and Denormals-Are-Zero (DAZ) mode (e.g. subnormal values are converted to 0 when used as input parameters) to provide fast hardware handled IEEE 754 computation.

    • Full IEEE754 compliance with ARM support code
    • Run-Fast mode for near IEEE754 compliance (hardware only)

    A good explanation on FTZ and DAZ can be found in
    x87 and SSE Floating Point Assists in IA-32: Flush-To-Zero (FTZ) and Denormals-Are-Zero (DAZ):

    FTZ and DAZ modes both handle the cases when invalid floating-point data occurs or is
    processed with underflow or denormal conditions. […]. The difference between a number
    that is handled by FTZ and DAZ is very subtle. FTZ handles underflow conditions while
    DAZ handles denormals. An underflow condition occurs when a computation results in a
    denormal. In this case, FTZ mode sets the output to zero. DAZ fixes the cases when
    denormals are used as input, either as constants or by reading invalid memory into
    registers. DAZ mode sets the inputs of the calculation to zero before computation. FTZ
    can then be said to handle [output] while DAZ handles [input].

    The only things about FTZ on Apple’s developer site seems to be in iOS ABI Function Call Guide :

    VFP status register |
    FPSCR |
    Special |
    Condition code bits (28-31) and saturation bits (0-4) are not preserved by function calls. Exception control (8-12), rounding mode (22-23), and flush-to-zero (24) bits should be modified only by specific routines that affect the application state (including framework API functions). Short vector length (16-18) and stride (20-21) bits must be zero on function entry and exit. All other bits must not be modified.

    According to ARM1176JZF-S Technical Reference Manual, 18.5
    Modes of operation (first iPhone processor), the VFP can be configured to fully support IEEE 754 (sub normal arithmetic), but in this case it will require some software support (trapping into kernel to compute in software).

    Note: I have also read Debian’s ARM Hard Float Port and VFP comparison pages.

    My questions are :

    • Where can one find definitive answers regarding subnormal numbers handling across iOS devices ?

    • Can one set the iOS system to provide support for subnormal number without asking the compiler to produce only full software floating point code ?

    Thanks.

    2 Solutions Collect From Internet About “subnormal IEEE 754 floating point numbers support on iOS ARM devices (iPhone 4)”

    Can one set the iOS system to provide support for subnormal number without asking the compiler to produce only full software floating point code?

    Yes. This can be achieved by setting the FZ bit in the FPSCR to zero:

    static inline void DisableFZ( )
    {
        __asm__ volatile("vmrs r0, fpscr\n"
                         "bic r0, $(1 << 24)\n"
                         "vmsr fpscr, r0" : : : "r0");
    }
    

    Note that this can cause significant slowdowns in application performance when appreciable quantities of denormal values are encountered. You can (and should) restore the default floating-point state before making calls into any code that does not make an ABI guarantee to work properly in non-default modes:

    static inline void RestoreFZ( ) {
        __asm__ volatile("vmrs r0, fpscr\n"
                         "orr r0, $(1 << 24)\n"
                         "vmsr fpscr, r0" : : : "r0");
    }
    

    Please file a bug report to request that better documentation be provided for the modes of FP operation in iOS.

    •Where can one find definitive answers regarding subnormal numbers
    

    handling across iOS devices ?

    You already found your answer. Its to be expected the ARM doesn’t have the same floating-point abilities.

    •Can one set the iOS system to provide support for subnormal number
    without asking the compiler to produce only full software floating
    point code ?

    I do not believe so, at least I would hope so, to get different numbers using the same value.