Tcl Source Code

View Ticket
Login
Ticket UUID: bf029ced86b614a4c29dc15b0ddc2b222e489004
Title: binary.test 40.3 signed NaN fails on IRIX/MIPS machines
Type: Bug Created on: 2017-01-11 21:22:44
Submitter: dexter1 Assigned to: nobody
Subsystem: 48. Number Handling Severity: Minor
Priority: 5 Medium Last modified: 2026-10-13 09:22:23
Status: Open Closed by: nobody
Resolution: None Closed on:
Version: 8.6.6
Description:
I've compiled tcl 8.6.6 from source.
System is a Challenge S server with MIPS R4400 processor. IRIX version is 6.5.22m and the compiler used is MIPSPro 7.4.4 with all available vendor-patches installed. CFLAGS are "-O2 -mips3 -n32"

When performing 'make test' it fails as follows:

==== binary-40.3 ScanNumber: NaN FAILED
==== Contents of test case:

    unset -nocomplain arg1
    list [binary scan \xff\xff\xff\xff f1 arg1] $arg1

---- Result was:
1 NaN(7ffffffffffff)
---- Result should have been (glob matching):
1 -NaN*
==== binary-40.3 FAILED

The test expects a single precision NaN with the sign bit set, because the original bit pattern's most significant bit is 1. A short version of this test is the following two-liner in tcl:

list [binary scan \xff\xff\xff\xff f1 arg1]
puts $arg1

which on the Challenge S produces:

cyane:~/tcltest> ../src/tcl8.6.6/unix/tcltest ./nan.tcl
NaN(7ffffffffffff)


It depends on the particular MIPS processor how the sign of a NaN result is stored and presented. Upon printing the NaN with a printf in C we discovered that the single precision NaN gets converted to a double precision NaN, with loss of the sign. An example:

#include <stdio.h>

int main(void)
{
        unsigned int i;
        unsigned long long x;

        x = 0xffffffffffffffff;
        printf("double of %llx is %f \n",x,*(double*)&x);

        x = 0x7fffffffffffffff;
        printf("double of %llx is %f \n",x,*(double*)&x);

        i = 0xffffffff;
        printf("float of %x is %f \n",i,*(float*)&i);

        i = 0x7fffffff;
        printf("float of %x is %f \n",i,*(float*)&i);

        return 0;
}

gives:

double of ffffffffffffffff is -nan0xffffffff 
double of 7fffffffffffffff is nan0xffffffff 
float of ffffffff is nan0x7fffffff 
float of 7fffffff is nan0x7fffffff 

This results happens for R4400 processors and R10000 processors as fellow enthusiasts have verified this. The double precision retains its sign, but the single precision does not. We believe that those processors handle conversion in hardware, different than for instance the R8000 processor. We haven't tested that processor yet however, due to the fact that they are very uncommon.

Because IEEE-754-2008 standard places no value to the sign bit and the NaN signs are not consistent on several MIPS Processors, i wonder if that explicit test for NaN with sign should be either be retained and disabled for IRIX or maybe weakened to disregard sign in the general case.
User Comments:
anonymous (claiming to be OOHehir) added on 2026-10-13 09:22:23:
binary-40.3 fails the same way on RISC-V (riscv64, SiFive U74 on a StarFive JH7110), with Tcl 9.1.0 & 8.6.18 built by the Yocto Project:

  ==== binary-40.3 ScanNumber: NaN FAILED
  ---- Result was:
  1 NaN
  ---- Result should have been (glob matching):
  1 -NaN*

On RISC-V the sign loss is required by the ISA rather than varying by implementation: unless an instruction says otherwise, any floating-point operation that produces a NaN returns the canonical NaN, which is positive.
ScanNumber passes the float to Tcl_NewDoubleObj(), & GCC compiles that float-to-double widening to fcvt.d.s, so a negative single-precision NaN always becomes a positive double NaN. A standalone test of the same widening (0xffffffff in, 0x7ff8000000000000 out) confirms it under qemu-riscv64.
IEEE 754 does not define the sign of a NaN produced by a conversion, so I agree with dropping the sign from the expected result, or accepting both.