Opened 6 years ago

Last modified 4 years ago

#8285 new bug

unexpected behavior with encodeFloat on large inputs

Reported by: carter Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.7
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description (last modified by thomie)

> encodeFloat 1 1023
8.98846567431158e307  -- ok

> encodeFloat 1 1024
Infinity  -- ok

> encodeFloat 1 (2^31 - 1)
Infinity  -- ok

> encodeFloat 1 (2^31)
0.0  -- not ok

Change History (8)

comment:1 Changed 6 years ago by carter

This seems like its worth fixing, if theres a reasonable solution. My understanding is the the current code just punts on handling these corner cases properly

comment:2 Changed 6 years ago by hvr

Fwiw, encodeFloat 1 (2^31) behaves just like the C99 function ldexp(3) does for those arguments.

PS: Now I see the problem,

Prelude> 2^31-1 :: Int
2147483647
Prelude> 2^31 :: Int
-2147483648
Last edited 6 years ago by hvr (previous) (diff)

comment:3 Changed 5 years ago by thoughtpolice

Milestone: 7.8.37.10.1

Moving to 7.10.1

comment:4 in reply to:  2 Changed 5 years ago by thomie

Replying to hvr:

PS: Now I see the problem

What is exactly the problem? That the second argument to encodeFloat is treated as a 32 bit integer?

comment:5 Changed 5 years ago by thoughtpolice

Milestone: 7.10.17.12.1

Moving to 7.12.1 milestone; if you feel this is an error and should be addressed sooner, please move it back to the 7.10.1 milestone.

comment:6 Changed 4 years ago by thoughtpolice

Milestone: 7.12.18.0.1

Milestone renamed

comment:7 in reply to:  2 Changed 4 years ago by thomie

Description: modified (diff)

I think this just needs an update to the encodeFloat docstring.

To confirms what hvr said in comment:2:

test.c:

#include <math.h>
#include <stdio.h>
#include <errno.h>
#include <fenv.h>
#include <limits.h>
#include <float.h>

void test(double x, int exp) {
  errno = 0;
  feclearexcept(FE_ALL_EXCEPT);
  printf("(%f)*2^(%d) = %f\n", x, exp, ldexp(x, exp));
  printf("errno: %d (ERANGE = %d), UNDERFLOW: %d, OVERFLOW: %d\n",
      errno, ERANGE,
      fetestexcept(FE_UNDERFLOW) == FE_UNDERFLOW,
      fetestexcept(FE_OVERFLOW) == FE_OVERFLOW);
}

void main() {
  // If the result overflows, a range error occurs, and the functions
  // return HUGE_VAL, HUGE_VALF, or HUGE_VALL, respectively, with a sign
  // the same as x.
  test(1, 1024);
  test(1, INT_MAX); // 2^31 - 1
  printf("\n");

  // If the result underflows, a range error occurs, and zero is
  // returned.
  test(1, DBL_MIN_EXP); // Not sure why not getting range error here,
  test(1, -1074); // or here.
  test(1, -1075); // but only starting here.
  test(1, 1 << 31);
  printf("\n");

  // If x is positive infinity (negative infinity), positive infinity
  // (negative infinity) is returned.
  test(HUGE_VAL, 1 << 31);
  test(- HUGE_VAL, 1 << 31);
}
$ gcc test.c -lm
$ ./a.out 
(1.000000)*2^(1024) = inf
errno: 34 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 1
(1.000000)*2^(2147483647) = inf
errno: 34 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 1

(1.000000)*2^(-1021) = 0.000000
errno: 0 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 0
(1.000000)*2^(-1074) = 0.000000
errno: 0 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 0
(1.000000)*2^(-1075) = 0.000000
errno: 34 (ERANGE = 34), UNDERFLOW: 1, OVERFLOW: 0
(1.000000)*2^(-2147483648) = 0.000000
errno: 34 (ERANGE = 34), UNDERFLOW: 1, OVERFLOW: 0

(inf)*2^(-2147483648) = inf
errno: 0 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 0
(-inf)*2^(-2147483648) = -inf
errno: 0 (ERANGE = 34), UNDERFLOW: 0, OVERFLOW: 0

comment:8 Changed 4 years ago by thomie

Milestone: 8.0.1
Note: See TracTickets for help on using tickets.