示例#1
0
/**
 * Evaluate the expression with the given parameters.
 * The order and number of parameters must match the names given to parse.
 */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr,
                                            const double *param_values,
                                            int param_values_len,
                                            double *r_result)
{
  *r_result = 0.0;

  if (!BLI_expr_pylike_is_valid(expr)) {
    return EXPR_PYLIKE_INVALID;
  }

#define FAIL_IF(condition) \
  if (condition) { \
    return EXPR_PYLIKE_FATAL_ERROR; \
  } \
  ((void)0)

  /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */
  FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000);

  double *stack = BLI_array_alloca(stack, expr->max_stack);

  /* Evaluate expression. */
  ExprOp *ops = expr->ops;
  int sp = 0, pc;

  feclearexcept(FE_ALL_EXCEPT);

  for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) {
    switch (ops[pc].opcode) {
      /* Arithmetic */
      case OPCODE_CONST:
        FAIL_IF(sp >= expr->max_stack);
        stack[sp++] = ops[pc].arg.dval;
        break;
      case OPCODE_PARAMETER:
        FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len);
        stack[sp++] = param_values[ops[pc].arg.ival];
        break;
      case OPCODE_FUNC1:
        FAIL_IF(sp < 1);
        stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]);
        break;
      case OPCODE_FUNC2:
        FAIL_IF(sp < 2);
        stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]);
        sp--;
        break;
      case OPCODE_MIN:
        FAIL_IF(sp < ops[pc].arg.ival);
        for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
          CLAMP_MAX(stack[sp - 2], stack[sp - 1]);
        }
        break;
      case OPCODE_MAX:
        FAIL_IF(sp < ops[pc].arg.ival);
        for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
          CLAMP_MIN(stack[sp - 2], stack[sp - 1]);
        }
        break;

      /* Jumps */
      case OPCODE_JMP:
        pc += ops[pc].jmp_offset;
        break;
      case OPCODE_JMP_ELSE:
        FAIL_IF(sp < 1);
        if (!stack[--sp]) {
          pc += ops[pc].jmp_offset;
        }
        break;
      case OPCODE_JMP_OR:
      case OPCODE_JMP_AND:
        FAIL_IF(sp < 1);
        if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) {
          pc += ops[pc].jmp_offset;
        }
        else {
          sp--;
        }
        break;

      /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */
      case OPCODE_CMP_CHAIN:
        FAIL_IF(sp < 2);
        /* If comparison fails, return 0 and jump to end. */
        if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) {
          stack[sp - 2] = 0.0;
          pc += ops[pc].jmp_offset;
        }
        /* Otherwise keep b on the stack and proceed. */
        else {
          stack[sp - 2] = stack[sp - 1];
        }
        sp--;
        break;

      default:
        return EXPR_PYLIKE_FATAL_ERROR;
    }
  }

  FAIL_IF(sp != 1 || pc != expr->ops_count);

#undef FAIL_IF

  *r_result = stack[0];

  /* Detect floating point evaluation errors. */
  int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
  if (flags) {
    return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO;
  }

  return EXPR_PYLIKE_SUCCESS;
}
示例#2
0
/*
 * Test fegetexcept(), fedisableexcept(), and feenableexcept().
 *
 * Prerequisites: fetestexcept(), feraiseexcept()
 */
static void
test_masking(void)
{
	struct sigaction act;
	int except, i, pass, raise, status;

	assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
	assert((feenableexcept(FE_INVALID|FE_OVERFLOW) & ALL_STD_EXCEPT) == 0);
	assert((feenableexcept(FE_UNDERFLOW) & ALL_STD_EXCEPT) ==
	    (FE_INVALID | FE_OVERFLOW));
	assert((fedisableexcept(FE_OVERFLOW) & ALL_STD_EXCEPT) ==
	    (FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW));
	assert((fegetexcept() & ALL_STD_EXCEPT) == (FE_INVALID | FE_UNDERFLOW));
	assert((fedisableexcept(FE_ALL_EXCEPT) & ALL_STD_EXCEPT) ==
	    (FE_INVALID | FE_UNDERFLOW));
	assert((fegetexcept() & ALL_STD_EXCEPT) == 0);

	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = trap_handler;
	for (pass = 0; pass < 2; pass++) {
		for (i = 0; i < NEXCEPTS; i++) {
			except = std_excepts[i];
			/* over/underflow may also raise inexact */
			if (except == FE_INEXACT)
				raise = FE_DIVBYZERO | FE_INVALID;
			else
				raise = ALL_STD_EXCEPT ^ except;

			/*
			 * We need to fork a child process because
			 * there isn't a portable way to recover from
			 * a floating-point exception.
			 */
			switch(fork()) {
			case 0:		/* child */
				assert((fegetexcept() & ALL_STD_EXCEPT) == 0);
				assert((feenableexcept(except)
					   & ALL_STD_EXCEPT) == 0);
				assert(fegetexcept() == except);
				raiseexcept(raise);
				assert(feraiseexcept(raise) == 0);
				assert(fetestexcept(ALL_STD_EXCEPT) == raise);

				assert(sigaction(SIGFPE, &act, NULL) == 0);
				switch (pass) {
				case 0:
					raiseexcept(except);
				case 1:
					feraiseexcept(except);
				default:
					assert(0);
				}
				assert(0);
			default:	/* parent */
				assert(wait(&status) > 0);
				/*
				 * Avoid assert() here so that it's possible
				 * to examine a failed child's core dump.
				 */
				if (!WIFEXITED(status))
					errx(1, "child aborted\n");
				assert(WEXITSTATUS(status) == 0);
				break;
			case -1:	/* error */
				assert(0);
			}
		}
	}
	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
}
bool IEEE754ExceptionsPlugin::checkIeee754DivByZeroExceptionFlag()
{
    return fetestexcept(FE_DIVBYZERO) != 0;
}
示例#4
0
__EXTERN_FUNC__ int inline correctFpException(esweep_object* obj) {
  int i;

  Wave *wave;
  Polar *polar;
  Complex *cpx;
  Surface *surf;

  if (fetestexcept(FE_INVALID)) {
    fprintf(stderr, "Invalid floating point operation occured.\n");
    feclearexcept(FE_INVALID);
    return 0;
  }

  if (fetestexcept(FE_OVERFLOW | FE_DIVBYZERO)) {
    // find the errors and correct them by rounding to neares representable
    switch (obj->type) {
      case WAVE:
        wave=(Wave*) obj->data;
        for (i=0; i < obj->size; i++) {
          if (isinf(wave[i])) {
            if (signbit(wave[i])) {
              wave[i]=-MAXREAL;
            } else {
              wave[i]=MAXREAL;
            }
          }
        }
        break;
      case POLAR:
        polar=(Polar*) obj->data;
        for (i=0; i < obj->size; i++) {
          if (isinf(polar[i].abs)) {
            if (signbit(polar[i].abs)) {
              polar[i].abs=-MAXREAL;
            } else {
              polar[i].abs=MAXREAL;
            }
          }
          if (isinf(polar[i].arg)) {
            if (signbit(polar[i].arg)) {
              polar[i].arg=-MAXREAL;
            } else {
              polar[i].arg=MAXREAL;
            }
          }
        }
        break;
      case COMPLEX:
        cpx=(Complex*) obj->data;
        for (i=0; i < obj->size; i++) {
          if (isinf(cpx[i].real)) {
            if (signbit(cpx[i].real)) {
              cpx[i].real=-MAXREAL;
            } else {
              cpx[i].real=MAXREAL;
            }
          }
          if (isinf(cpx[i].imag)) {
            if (signbit(cpx[i].imag)) {
              cpx[i].imag=-MAXREAL;
            } else {
              cpx[i].imag=MAXREAL;
            }
          }
        }
        break;
      case SURFACE:
      default:
        break;
    }
    feclearexcept(FE_OVERFLOW | FE_DIVBYZERO);
  }
  return 1;
}
示例#5
0
static int
do_test (void)
{
  int result = 0;

#ifndef NO_LONG_DOUBLE
  {
    long double x = 0x100000001ll + (long double) 0.5;
    long double q;
    long double r;

    r = modfl (x, &q);
    if (q != (long double) 0x100000001ll || r != 0.5)
      {
	printf ("modfl (%Lg, ...) failed\n", x);
	result = 1;
      }
  }

  {
    long double x;
    long double m;
    long double r;
    int e;
    int i;

# if LDBL_MANT_DIG == 64
    m = 0xf.fffffffffffffffp-4L;
# elif LDBL_MANT_DIG == 106
    /* This has to match the mantissa of LDBL_MAX which actually does have a
       missing bit in the middle.  */
    m = 0x1.fffffffffffff7ffffffffffff8p-1L;
# elif LDBL_MANT_DIG == 113
    m = 0x1.ffffffffffffffffffffffffffffp-1L;
# else
#  error "Please adjust"
# endif

    for (i = LDBL_MAX_EXP, x = LDBL_MAX; i >= LDBL_MIN_EXP; --i, x /= 2.0L)
      {
	printf ("2^%d: ", i);

	r = frexpl (x, &e);
	if (r != m)
	  {
	    printf ("mantissa incorrect: %.20La\n", r);
	    result = 1;
	    continue;
	  }
	if (e != i)
	  {
	    printf ("exponent wrong %d (%.20Lg)\n", e, x);
	    result = 1;
	    continue;
	  }
	puts ("ok");
      }

    for (i = LDBL_MIN_EXP, x = LDBL_MIN; i >= LDBL_MIN_EXP - LDBL_MANT_DIG + 1;
	 --i, x /= 2.0L)
      {
        printf ("2^%d: ", i);

        r = frexpl (x, &e);
        if (r != 0.5L)
          {
            printf ("mantissa incorrect: %.20La\n", r);
            result = 1;
            continue;
          }
        if (e != i)
          {
            printf ("exponent wrong %d (%.20Lg)\n", e, x);
            result = 1;
            continue;
          }
        puts ("ok");
      }

  }

# if 0
  {
    int e;
    long double r = frexpl (LDBL_MIN * LDBL_EPSILON, &e);

    if (r != 0.5)
      {
	printf ("frexpl (LDBL_MIN * LDBL_EPSILON, ...): mantissa wrong: %Lg\n",
		r);
	result = 1;
      }
    else if (e != -16444)
      {
	printf ("frexpl (LDBL_MIN * LDBL_EPSILON, ...): exponent wrong: %d\n",
		e);
	result = 1;
      }
  }
# endif
#endif

  {
    double x = 0x100000001ll + (double) 0.5;
    double q;
    double r;

    r = modf (x, &q);
    if (q != (double) 0x100000001ll || r != 0.5)
      {
	printf ("modf (%g, ...) failed\n", x);
	result = 1;
      }
  }

  {
    union ieee754_float v1;
    union ieee754_float v2;
    float f;

    v1.f = f = FLT_MIN;
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (FLT_MIN) failed: %d\n", fpclassify (f));
	result = 1;
      }
    f = nextafterf (f, FLT_MIN / 2.0f);
    if (fpclassify (f) != FP_SUBNORMAL)
      {
	printf ("fpclassify (FLT_MIN-epsilon) failed: %d\n", fpclassify (f));
	result = 1;
      }
    v2.f = f = nextafterf (f, FLT_MIN);
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (FLT_MIN-epsilon+epsilon) failed: %d\n",
		fpclassify (f));
	result = 1;
      }

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("FLT_MIN: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("FLT_MIN: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("FLT_MIN: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.f = f = -FLT_MIN;
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (-FLT_MIN) failed: %d\n", fpclassify (f));
	result = 1;
      }
    f = nextafterf (f, -FLT_MIN / 2.0f);
    if (fpclassify (f) != FP_SUBNORMAL)
      {
	printf ("fpclassify (-FLT_MIN-epsilon) failed: %d\n", fpclassify (f));
	result = 1;
      }
    v2.f = f = nextafterf (f, -FLT_MIN);
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (-FLT_MIN-epsilon+epsilon) failed: %d\n",
		fpclassify (f));
	result = 1;
      }

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("-FLT_MIN: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-FLT_MIN: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-FLT_MIN: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    f = FLT_MAX;
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (FLT_MAX) failed: %d\n", fpclassify (f));
	result = 1;
      }
    f = nextafterf (f, INFINITY);
    if (fpclassify (f) != FP_INFINITE)
      {
	printf ("fpclassify (FLT_MAX+epsilon) failed: %d\n", fpclassify (f));
	result = 1;
      }

    f = -FLT_MAX;
    if (fpclassify (f) != FP_NORMAL)
      {
	printf ("fpclassify (-FLT_MAX) failed: %d\n", fpclassify (f));
	result = 1;
      }
    f = nextafterf (f, -INFINITY);
    if (fpclassify (f) != FP_INFINITE)
      {
	printf ("fpclassify (-FLT_MAX-epsilon) failed: %d\n", fpclassify (f));
	result = 1;
      }

    v1.f = f = 0.0625;
    f = nextafterf (f, 0.0);
    v2.f = f = nextafterf (f, 1.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("0.0625f down: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0625f down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("0.0625f down: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.f = f = 0.0625;
    f = nextafterf (f, 1.0);
    v2.f = f = nextafterf (f, 0.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("0.0625f up: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0625f up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("0.0625f up: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.f = f = -0.0625;
    f = nextafterf (f, 0.0);
    v2.f = f = nextafterf (f, -1.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("-0.0625f up: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-0.0625f up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-0.0625f up: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.f = f = -0.0625;
    f = nextafterf (f, -1.0);
    v2.f = f = nextafterf (f, 0.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("-0.0625f down: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-0.0625f down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-0.0625f down: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.f = f = 0.0f;
    f = nextafterf (f, 1.0);
    v2.f = nextafterf (f, -1.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("0.0f up: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0f up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (0 != v2.ieee.negative)
      {
	printf ("0.0f up: negative differs: 0 vs %d\n",
		v2.ieee.negative);
	result = 1;
      }

    v1.f = f = 0.0f;
    f = nextafterf (f, -1.0);
    v2.f = nextafterf (f, 1.0);

    if (v1.ieee.mantissa != v2.ieee.mantissa)
      {
	printf ("0.0f down: mantissa differs: %8x vs %8x\n",
		v1.ieee.mantissa, v2.ieee.mantissa);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0f down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (1 != v2.ieee.negative)
      {
	printf ("0.0f down: negative differs: 1 vs %d\n",
		v2.ieee.negative);
	result = 1;
      }

    if (nextafterf (0.0f, INFINITY) != nextafterf (0.0f, 1.0f)
        || nextafterf (-0.0f, INFINITY) != nextafterf (-0.0f, 1.0f)
        || nextafterf (0.0f, -INFINITY) != nextafterf (0.0f, -1.0f)
        || nextafterf (-0.0f, -INFINITY) != nextafterf (-0.0f, -1.0f))
      {
	printf ("nextafterf (+-0, +-Inf) != nextafterf (+-0, +-1)\n");
	result = 1;
      }

    if (nexttowardf (0.0f, INFINITY) != nexttowardf (0.0f, 1.0f)
        || nexttowardf (-0.0f, INFINITY) != nexttowardf (-0.0f, 1.0f)
        || nexttowardf (0.0f, -INFINITY) != nexttowardf (0.0f, -1.0f)
        || nexttowardf (-0.0f, -INFINITY) != nexttowardf (-0.0f, -1.0f))
      {
	printf ("nexttowardf (+-0, +-Inf) != nexttowardf (+-0, +-1)\n");
	result = 1;
      }
  }

  {
    union ieee754_double v1;
    union ieee754_double v2;
    double d;

    v1.d = d = DBL_MIN;
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (DBL_MIN) failed: %d\n", fpclassify (d));
	result = 1;
      }
    d = nextafter (d, DBL_MIN / 2.0);
    if (fpclassify (d) != FP_SUBNORMAL)
      {
	printf ("fpclassify (DBL_MIN-epsilon) failed: %d\n", fpclassify (d));
	result = 1;
      }
    v2.d = d = nextafter (d, DBL_MIN);
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (DBL_MIN-epsilon+epsilon) failed: %d\n",
		fpclassify (d));
	result = 1;
      }

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("DBL_MIN: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("DBL_MIN: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("DBL_MIN: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("DBL_MIN: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.d = d = -DBL_MIN;
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (-DBL_MIN) failed: %d\n", fpclassify (d));
	result = 1;
      }
    d = nextafter (d, -DBL_MIN / 2.0);
    if (fpclassify (d) != FP_SUBNORMAL)
      {
	printf ("fpclassify (-DBL_MIN-epsilon) failed: %d\n", fpclassify (d));
	result = 1;
      }
    v2.d = d = nextafter (d, -DBL_MIN);
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (-DBL_MIN-epsilon+epsilon) failed: %d\n",
		fpclassify (d));
	result = 1;
      }

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("-DBL_MIN: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("-DBL_MIN: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-DBL_MIN: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-DBL_MIN: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    d = DBL_MAX;
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (DBL_MAX) failed: %d\n", fpclassify (d));
	result = 1;
      }
    d = nextafter (d, INFINITY);
    if (fpclassify (d) != FP_INFINITE)
      {
	printf ("fpclassify (DBL_MAX+epsilon) failed: %d\n", fpclassify (d));
	result = 1;
      }

    d = -DBL_MAX;
    if (fpclassify (d) != FP_NORMAL)
      {
	printf ("fpclassify (-DBL_MAX) failed: %d\n", fpclassify (d));
	result = 1;
      }
    d = nextafter (d, -INFINITY);
    if (fpclassify (d) != FP_INFINITE)
      {
	printf ("fpclassify (-DBL_MAX-epsilon) failed: %d\n", fpclassify (d));
	result = 1;
      }

    v1.d = d = 0.0625;
    d = nextafter (d, 0.0);
    v2.d = d = nextafter (d, 1.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("0.0625 down: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("0.0625 down: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0625 down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("0.0625 down: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.d = d = 0.0625;
    d = nextafter (d, 1.0);
    v2.d = d = nextafter (d, 0.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("0.0625 up: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("0.0625 up: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0625 up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("0.0625 up: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.d = d = -0.0625;
    d = nextafter (d, 0.0);
    v2.d = d = nextafter (d, -1.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("-0.0625 up: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("-0.0625 up: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-0.0625 up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-0.0625 up: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.d = d = -0.0625;
    d = nextafter (d, -1.0);
    v2.d = d = nextafter (d, 0.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("-0.0625 down: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("-0.0625 down: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("-0.0625 down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (v1.ieee.negative != v2.ieee.negative)
      {
	printf ("-0.0625 down: negative differs: %d vs %d\n",
		v1.ieee.negative, v2.ieee.negative);
	result = 1;
      }

    v1.d = d = 0.0;
    d = nextafter (d, 1.0);
    v2.d = nextafter (d, -1.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("0.0 up: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("0.0 up: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0 up: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (0 != v2.ieee.negative)
      {
	printf ("0.0 up: negative differs: 0 vs %d\n",
		v2.ieee.negative);
	result = 1;
      }

    v1.d = d = 0.0;
    d = nextafter (d, -1.0);
    v2.d = nextafter (d, 1.0);

    if (v1.ieee.mantissa0 != v2.ieee.mantissa0)
      {
	printf ("0.0 down: mantissa0 differs: %8x vs %8x\n",
		v1.ieee.mantissa0, v2.ieee.mantissa0);
	result = 1;
      }
    if (v1.ieee.mantissa1 != v2.ieee.mantissa1)
      {
	printf ("0.0 down: mantissa1 differs: %8x vs %8x\n",
		v1.ieee.mantissa1, v2.ieee.mantissa1);
	result = 1;
      }
    if (v1.ieee.exponent != v2.ieee.exponent)
      {
	printf ("0.0 down: exponent differs: %4x vs %4x\n",
		v1.ieee.exponent, v2.ieee.exponent);
	result = 1;
      }
    if (1 != v2.ieee.negative)
      {
	printf ("0.0 down: negative differs: 1 vs %d\n",
		v2.ieee.negative);
	result = 1;
      }

    if (nextafter (0.0, INFINITY) != nextafter (0.0, 1.0)
        || nextafter (-0.0, INFINITY) != nextafter (-0.0, 1.0)
        || nextafter (0.0, -INFINITY) != nextafter (0.0, -1.0)
        || nextafter (-0.0, -INFINITY) != nextafter (-0.0, -1.0))
      {
	printf ("nextafter (+-0, +-Inf) != nextafter (+-0, +-1)\n");
	result = 1;
      }

    if (nexttoward (0.0, INFINITY) != nexttoward (0.0, 1.0)
        || nexttoward (-0.0, INFINITY) != nexttoward (-0.0, 1.0)
        || nexttoward (0.0, -INFINITY) != nexttoward (0.0, -1.0)
        || nexttoward (-0.0, -INFINITY) != nexttoward (-0.0, -1.0))
      {
	printf ("nexttoward (+-0, +-Inf) != nexttoward (+-0, +-1)\n");
	result = 1;
      }
  }

#ifndef NO_LONG_DOUBLE
  {
    long double v1, v2;

    v1 = LDBL_MIN;
    if (fpclassify (v1) != FP_NORMAL)
      {
	printf ("fpclassify (LDBL_MIN) failed: %d (%La)\n",
		fpclassify (v1), v1);
	result = 1;
      }
    v2 = nextafterl (v1, LDBL_MIN / 2.0);
    if (fpclassify (v2) != FP_SUBNORMAL)
      {
	printf ("fpclassify (LDBL_MIN-epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }
    v2 = nextafterl (v2, LDBL_MIN);
    if (fpclassify (v2) != FP_NORMAL)
      {
	printf ("fpclassify (LDBL_MIN-epsilon+epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }

    if (v1 != v2)
      {
	printf ("LDBL_MIN-epsilon+epsilon != LDBL_MIN: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = -LDBL_MIN;
    if (fpclassify (v1) != FP_NORMAL)
      {
	printf ("fpclassify (-LDBL_MIN) failed: %d (%La)\n",
		fpclassify (v1), v1);
	result = 1;
      }
    v2 = nextafterl (v1, -LDBL_MIN / 2.0);
    if (fpclassify (v2) != FP_SUBNORMAL)
      {
	printf ("fpclassify (-LDBL_MIN-epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }
    v2 = nextafterl (v2, -LDBL_MIN);
    if (fpclassify (v2) != FP_NORMAL)
      {
	printf ("fpclassify (-LDBL_MIN-epsilon+epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }

    if (v1 != v2)
      {
	printf ("-LDBL_MIN-epsilon+epsilon != -LDBL_MIN: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = LDBL_MAX;
    if (fpclassify (v1) != FP_NORMAL)
      {
	printf ("fpclassify (LDBL_MAX) failed: %d (%La)\n",
		fpclassify (v1), v1);
	result = 1;
      }
    v2 = nextafterl (v1, INFINITY);
    if (fpclassify (v2) != FP_INFINITE)
      {
	printf ("fpclassify (LDBL_MAX+epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }

    v1 = -LDBL_MAX;
    if (fpclassify (v1) != FP_NORMAL)
      {
	printf ("fpclassify (-LDBL_MAX) failed: %d (%La)\n",
		fpclassify (v1), v1);
	result = 1;
      }
    v2 = nextafterl (v1, -INFINITY);
    if (fpclassify (v2) != FP_INFINITE)
      {
	printf ("fpclassify (-LDBL_MAX-epsilon) failed: %d (%La)\n",
		fpclassify (v2), v2);
	result = 1;
      }

    v1 = 0.0625;
    v2 = nextafterl (v1, 0.0);
    v2 = nextafterl (v2, 1.0);

    if (v1 != v2)
      {
	printf ("0.0625L-epsilon+epsilon != 0.0625L: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = 0.0625;
    v2 = nextafterl (v1, 1.0);
    v2 = nextafterl (v2, 0.0);

    if (v1 != v2)
      {
	printf ("0.0625L+epsilon-epsilon != 0.0625L: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = -0.0625;
    v2 = nextafterl (v1, 0.0);
    v2 = nextafterl (v2, -1.0);

    if (v1 != v2)
      {
	printf ("-0.0625L+epsilon-epsilon != -0.0625L: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = -0.0625;
    v2 = nextafterl (v1, -1.0);
    v2 = nextafterl (v2, 0.0);

    if (v1 != v2)
      {
	printf ("-0.0625L-epsilon+epsilon != -0.0625L: %La vs %La\n", v2, v1);
	result = 1;
      }

    v1 = 0.0;
    v2 = nextafterl (v1, 1.0);
    v2 = nextafterl (v2, -1.0);

    if (v1 != v2)
      {
	printf ("0.0+epsilon-epsilon != 0.0L: %La vs %La\n", v2, v1);
	result = 1;
      }
    if (signbit (v2))
      {
	printf ("0.0+epsilon-epsilon is negative\n");
	result = 1;
      }

    v1 = 0.0;
    v2 = nextafterl (v1, -1.0);
    v2 = nextafterl (v2, 1.0);

    if (v1 != v2)
      {
	printf ("0.0-epsilon+epsilon != 0.0L: %La vs %La\n", v2, v1);
	result = 1;
      }
    if (!signbit (v2))
      {
	printf ("0.0-epsilon+epsilon is positive\n");
	result = 1;
      }

    if (nextafterl (0.0, INFINITY) != nextafterl (0.0, 1.0)
        || nextafterl (-0.0, INFINITY) != nextafterl (-0.0, 1.0)
        || nextafterl (0.0, -INFINITY) != nextafterl (0.0, -1.0)
        || nextafterl (-0.0, -INFINITY) != nextafterl (-0.0, -1.0))
      {
	printf ("nextafterl (+-0, +-Inf) != nextafterl (+-0, +-1)\n");
	result = 1;
      }

    if (nexttowardl (0.0L, INFINITY) != nexttowardl (0.0L, 1.0L)
        || nexttowardl (-0.0L, INFINITY) != nexttowardl (-0.0L, 1.0L)
        || nexttowardl (0.0L, -INFINITY) != nexttowardl (0.0L, -1.0L)
        || nexttowardl (-0.0L, -INFINITY) != nexttowardl (-0.0L, -1.0L))
      {
	printf ("nexttowardl (+-0, +-Inf) != nexttowardl (+-0, +-1)\n");
	result = 1;
      }
  }
#endif

  if (! isnormal (FLT_MIN))
    {
      puts ("isnormal (FLT_MIN) failed");
      result = 1;
    }
  if (! isnormal (DBL_MIN))
    {
      puts ("isnormal (DBL_MIN) failed");
      result = 1;
    }
#ifndef NO_LONG_DOUBLE
  if (! isnormal (LDBL_MIN))
    {
      puts ("isnormal (LDBL_MIN) failed");
      result = 1;
    }
#endif

#if defined (__i386__) || defined (__x86_64__)
  /* This is a test for the strange long doubles in x86 FPUs.  */
  {
    union
    {
      char b[10];
      long double d;
    } u =
      { .b = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0 } };

    if (fpclassify (u.d) != FP_NORMAL)
      {
	printf ("fpclassify (0x00008000000000000000) failed: %d (%Lg)\n",
		fpclassify (u.d), u.d);
	result = 1;
      }
  }

  /* Special qNaNs in x86 long double.  Test for scalbl.  */
  {
    union
    {
      char b[10];
      long double d;
    } u =
      { .b = { 0, 1, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f } };
    long double r;

    r = scalbl (u.d, 0.0);
    if (!isnan (r))
      {
	puts ("scalbl (qNaN, 0) does not return NaN");
	result = 1;
      }
    else if (memcmp (&r, &u.d, sizeof (double)) != 0)
      {
	puts ("scalbl (qNaN, 0) does not return the same NaN");
	result = 1;
      }
  }
#endif

#ifndef NO_LONG_DOUBLE
  {
    long double r;

    feclearexcept (FE_ALL_EXCEPT);
    r = scalbl (LDBL_MIN, 2147483647);
    if (! isinf (r))
      {
	puts ("scalbl (LDBL_MIN, 2147483647) does not return Inf");
	result = 1;
      }
    else if (signbit (r) != 0)
      {
	puts ("scalbl (LDBL_MIN, 2147483647) returns -Inf");
	result = 1;
      }
    else if (fetestexcept (FE_UNDERFLOW))
      {
	puts ("scalbl (LDBL_MIN, 2147483647) raises underflow exception");
	result = 1;
      }

    feclearexcept (FE_ALL_EXCEPT);
    r = scalbl (LDBL_MAX, -2147483647);
    if (r != 0.0)
      {
	puts ("scalbl (LDBL_MAX, -2147483647) does not return 0");
	result = 1;
      }
    else if (signbit (r) != 0)
      {
	puts ("scalbl (LDBL_MAX, -2147483647) returns -Inf");
	result = 1;
      }
    else if (fetestexcept (FE_OVERFLOW))
      {
	puts ("scalbl (LDBL_MAX, -2147483647) raises overflow exception");
	result = 1;
      }
  }
#endif

  /* The tests here are very similar to tests earlier in this file,
     the important difference is just that there are no intervening
     union variables that cause some GCC versions to hide possible
     bugs in nextafter* implementation.  */
  if (nextafterf (nextafterf (FLT_MIN, FLT_MIN / 2.0), FLT_MIN) != FLT_MIN)
    {
      puts ("nextafterf FLT_MIN test failed");
      result = 1;
    }
  if (nextafterf (nextafterf (-FLT_MIN, -FLT_MIN / 2.0), -FLT_MIN)
      != -FLT_MIN)
    {
      puts ("nextafterf -FLT_MIN test failed");
      result = 1;
    }
  if (nextafter (nextafter (DBL_MIN, DBL_MIN / 2.0), DBL_MIN) != DBL_MIN)
    {
      puts ("nextafter DBL_MIN test failed");
      result = 1;
    }
  if (nextafter (nextafter (-DBL_MIN, -DBL_MIN / 2.0), -DBL_MIN) != -DBL_MIN)
    {
      puts ("nextafter -DBL_MIN test failed");
      result = 1;
    }
#ifndef NO_LONG_DOUBLE
  if (nextafterl (nextafterl (LDBL_MIN, LDBL_MIN / 2.0), LDBL_MIN)
      != LDBL_MIN)
    {
      puts ("nextafterl LDBL_MIN test failed");
      result = 1;
    }
  if (nextafterl (nextafterl (-LDBL_MIN, -LDBL_MIN / 2.0), -LDBL_MIN)
      != -LDBL_MIN)
    {
      puts ("nextafterl -LDBL_MIN test failed");
      result = 1;
    }
#endif

  volatile float f1 = FLT_MAX;
  volatile float f2 = FLT_MAX / 2;
  (void) &f1;
  (void) &f2;
  feclearexcept (FE_ALL_EXCEPT);
  f2 += f1;
#if defined(FE_OVERFLOW) && defined(FE_INEXACT)
  int fe = fetestexcept (FE_ALL_EXCEPT);
  if (EXCEPTION_TESTS (float) && fe != (FE_OVERFLOW | FE_INEXACT))
    {
      printf ("float overflow test failed: %x\n", fe);
      result = 1;
    }
#endif

  volatile double d1 = DBL_MAX;
  volatile double d2 = DBL_MAX / 2;
  (void) &d1;
  (void) &d2;
  feclearexcept (FE_ALL_EXCEPT);
  d2 += d1;
#if defined(FE_OVERFLOW) && defined(FE_INEXACT)
  fe = fetestexcept (FE_ALL_EXCEPT);
  if (EXCEPTION_TESTS (double) && fe != (FE_OVERFLOW | FE_INEXACT))
    {
      printf ("double overflow test failed: %x\n", fe);
      result = 1;
    }
#endif

#ifndef NO_LONG_DOUBLE
  volatile long double ld1 = LDBL_MAX;
  volatile long double ld2 = LDBL_MAX / 2;
  (void) &ld1;
  (void) &ld2;
  feclearexcept (FE_ALL_EXCEPT);
  ld2 += ld1;
# if defined(FE_OVERFLOW) && defined(FE_INEXACT)
  fe = fetestexcept (FE_ALL_EXCEPT);
  if (EXCEPTION_TESTS (long double) && fe != (FE_OVERFLOW | FE_INEXACT))
    {
      printf ("long double overflow test failed: %x\n", fe);
      result = 1;
    }
# endif
#endif

#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG == 113
  volatile long double ld3 = 0x1.0000000000010000000100000001p+1;
  volatile long double ld4 = 0x1.0000000000000000000000000001p+1;
  (void) &ld3;
  (void) &ld4;
  ld3 -= ld4;
  if (ld3 != 0x1.0p-47)
    {
      printf ("long double subtraction test failed %.28La\n", ld3);
      result = 1;
    }
#endif

/* Skip testing IBM long double format, for 2 reasons:
   1) it only supports FE_TONEAREST
   2) nextafter (0.0, 1.0) == nextafterl (0.0L, 1.0L), so
      nextafter (0.0, 1.0) / 16.0L will be 0.0L.  */
#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG >= DBL_MANT_DIG + 4 \
    && LDBL_MANT_DIG != 106
  int oldmode = fegetround ();
  int j;
  for (j = 0; j < 4; j++)
    {
      int mode;
      int i;
      int k = 0;
      const char *mstr;
      switch (j)
	{
#ifdef FE_TONEAREST
	case 0:
	  mode = FE_TONEAREST;
	  mstr = "nearest";
	  k = 8;
	  break;
#endif
#ifdef FE_DOWNWARD
	case 1:
	  mode = FE_DOWNWARD;
	  mstr = "-inf";
	  break;
#endif
#ifdef FE_UPWARD
	case 2:
	  mode = FE_UPWARD;
	  mstr = "+inf";
	  k = 15;
	  break;
#endif
#ifdef FE_TOWARDZERO
	case 3:
	  mode = FE_TOWARDZERO;
	  mstr = "0";
	  break;
#endif
	default:
	  continue;
	}

      volatile long double ld5 = nextafter (0.0, 1.0) / 16.0L;
      volatile double d5;
      (void) &ld5;
      for (i = 0; i <= 32; i++)
	{
	  if (fesetround (mode))
	    {
	      printf ("failed to set rounding mode to %s\n", mstr);
	      if (ROUNDING_TESTS (long double, mode)
		  && ROUNDING_TESTS (double, mode))
		result = 1;
	      else
		puts ("ignoring this failure");
	      break;
	    }
	  d5 = ld5 * i;
	  (void) &d5;
	  fesetround (oldmode);
	  if (d5 != ((j == 0 && i == 8) ? 0 : (i + k) / 16)
		    * nextafter (0.0, 1.0))
	    {
	      printf ("%La incorrectly rounded to %s as %a\n",
		      ld5 * i, mstr, d5);
	      if (ROUNDING_TESTS (long double, mode)
		  && ROUNDING_TESTS (double, mode))
		result = 1;
	      else
		puts ("ignoring this failure");
	    }
bool IEEE754ExceptionsPlugin::checkIeee754InexactExceptionFlag()
{
    return fetestexcept(FE_INEXACT) != 0;
}
示例#7
0
int fegetexceptflag(fexcept_t *fp, int mask)
{
	*fp = fetestexcept(mask);
	return 0;
}
示例#8
0
	unsigned int fpe_test( unsigned int except )
	{
		return (unsigned int)fetestexcept( (int)except );
	}
示例#9
0
文件: fp.c 项目: IgorStepanov/dmd
 int testFE()
 {
     return fetestexcept(FE_ALL_EXCEPT);
 }
示例#10
0
文件: fmal.c 项目: 4ian/emscripten
/*
 * Fused multiply-add: Compute x * y + z with a single rounding error.
 *
 * We use scaling to avoid overflow/underflow, along with the
 * canonical precision-doubling technique adapted from:
 *
 *      Dekker, T.  A Floating-Point Technique for Extending the
 *      Available Precision.  Numer. Math. 18, 224-242 (1971).
 */
long double fmal(long double x, long double y, long double z)
{
	#pragma STDC FENV_ACCESS ON
	long double xs, ys, zs, adj;
	struct dd xy, r;
	int oround;
	int ex, ey, ez;
	int spread;

	/*
	 * Handle special cases. The order of operations and the particular
	 * return values here are crucial in handling special cases involving
	 * infinities, NaNs, overflows, and signed zeroes correctly.
	 */
	if (!isfinite(x) || !isfinite(y))
		return (x * y + z);
	if (!isfinite(z))
		return (z);
	if (x == 0.0 || y == 0.0)
		return (x * y + z);
	if (z == 0.0)
		return (x * y);

	xs = frexpl(x, &ex);
	ys = frexpl(y, &ey);
	zs = frexpl(z, &ez);
	oround = fegetround();
	spread = ex + ey - ez;

	/*
	 * If x * y and z are many orders of magnitude apart, the scaling
	 * will overflow, so we handle these cases specially.  Rounding
	 * modes other than FE_TONEAREST are painful.
	 */
	if (spread < -LDBL_MANT_DIG) {
#ifdef FE_INEXACT
		feraiseexcept(FE_INEXACT);
#endif
#ifdef FE_UNDERFLOW
		if (!isnormal(z))
			feraiseexcept(FE_UNDERFLOW);
#endif
		switch (oround) {
		default: /* FE_TONEAREST */
			return (z);
#ifdef FE_TOWARDZERO
		case FE_TOWARDZERO:
			if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
				return (z);
			else
				return (nextafterl(z, 0));
#endif
#ifdef FE_DOWNWARD
		case FE_DOWNWARD:
			if (x > 0.0 ^ y < 0.0)
				return (z);
			else
				return (nextafterl(z, -INFINITY));
#endif
#ifdef FE_UPWARD
		case FE_UPWARD:
			if (x > 0.0 ^ y < 0.0)
				return (nextafterl(z, INFINITY));
			else
				return (z);
#endif
		}
	}
	if (spread <= LDBL_MANT_DIG * 2)
		zs = scalbnl(zs, -spread);
	else
		zs = copysignl(LDBL_MIN, zs);

	fesetround(FE_TONEAREST);

	/*
	 * Basic approach for round-to-nearest:
	 *
	 *     (xy.hi, xy.lo) = x * y           (exact)
	 *     (r.hi, r.lo)   = xy.hi + z       (exact)
	 *     adj = xy.lo + r.lo               (inexact; low bit is sticky)
	 *     result = r.hi + adj              (correctly rounded)
	 */
	xy = dd_mul(xs, ys);
	r = dd_add(xy.hi, zs);

	spread = ex + ey;

	if (r.hi == 0.0) {
		/*
		 * When the addends cancel to 0, ensure that the result has
		 * the correct sign.
		 */
		fesetround(oround);
		volatile long double vzs = zs; /* XXX gcc CSE bug workaround */
		return xy.hi + vzs + scalbnl(xy.lo, spread);
	}

	if (oround != FE_TONEAREST) {
		/*
		 * There is no need to worry about double rounding in directed
		 * rounding modes.
		 * But underflow may not be raised correctly, example in downward rounding:
		 * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L)
		 */
		long double ret;
#if defined(FE_INEXACT) && defined(FE_UNDERFLOW)
		int e = fetestexcept(FE_INEXACT);
		feclearexcept(FE_INEXACT);
#endif
		fesetround(oround);
		adj = r.lo + xy.lo;
		ret = scalbnl(r.hi + adj, spread);
#if defined(FE_INEXACT) && defined(FE_UNDERFLOW)
		if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT))
			feraiseexcept(FE_UNDERFLOW);
		else if (e)
			feraiseexcept(FE_INEXACT);
#endif
		return ret;
	}

	adj = add_adjusted(r.lo, xy.lo);
	if (spread + ilogbl(r.hi) > -16383)
		return scalbnl(r.hi + adj, spread);
	else
		return add_and_denormalize(r.hi, adj, spread);
}
示例#11
0
int
main(int argc, char *argv[])
{
	static const int ntests = sizeof(tests) / sizeof(tests[0]) / 2;
	complex float in;
	complex long double expected;
	int i;

	printf("1..%d\n", ntests * 3);

	for (i = 0; i < ntests; i++) {
		__real__ expected = __real__ in = tests[2 * i];
		__imag__ in = tests[2 * i + 1];
		__imag__ expected = -cimag(in);

		assert(fpequal(libcrealf(in), __real__ in));
		assert(fpequal(libcreal(in), __real__ in));
		assert(fpequal(libcreall(in), __real__ in));
		assert(fpequal(libcimagf(in), __imag__ in));
		assert(fpequal(libcimag(in), __imag__ in));
		assert(fpequal(libcimagl(in), __imag__ in));		

		feclearexcept(FE_ALL_EXCEPT);
		if (!cfpequal(libconjf(in), expected)) {
			printf("not ok %d\t# conjf(%#.2g + %#.2gI): "
			       "wrong value\n",
			       3 * i + 1, creal(in), cimag(in));
		} else if (fetestexcept(FE_ALL_EXCEPT)) {
			printf("not ok %d\t# conjf(%#.2g + %#.2gI): "
			       "threw an exception\n",
			       3 * i + 1, creal(in), cimag(in));
		} else {
			printf("ok %d\t\t# conjf(%#.2g + %#.2gI)\n",
			       3 * i + 1, creal(in), cimag(in));
		}

		feclearexcept(FE_ALL_EXCEPT);
		if (!cfpequal(libconj(in), expected)) {
			printf("not ok %d\t# conj(%#.2g + %#.2gI): "
			       "wrong value\n",
			       3 * i + 2, creal(in), cimag(in));
		} else if (fetestexcept(FE_ALL_EXCEPT)) {
			printf("not ok %d\t# conj(%#.2g + %#.2gI): "
			       "threw an exception\n",
			       3 * i + 2, creal(in), cimag(in));
		} else {
			printf("ok %d\t\t# conj(%#.2g + %#.2gI)\n",
			       3 * i + 2, creal(in), cimag(in));
		}

		feclearexcept(FE_ALL_EXCEPT);
		if (!cfpequal(libconjl(in), expected)) {
			printf("not ok %d\t# conjl(%#.2g + %#.2gI): "
			       "wrong value\n",
			       3 * i + 3, creal(in), cimag(in));
		} else if (fetestexcept(FE_ALL_EXCEPT)) {
			printf("not ok %d\t# conjl(%#.2g + %#.2gI): "
			       "threw an exception\n",
			       3 * i + 3, creal(in), cimag(in));
		} else {
			printf("ok %d\t\t# conjl(%#.2g + %#.2gI)\n",
			       3 * i + 3, creal(in), cimag(in));
		}
	}

	return (0);
}
示例#12
0
static void NN_chain_core(const t_index N, t_float * const D, t_members * const members, cluster_result & Z2) {
/*
    N: integer
    D: condensed distance matrix N*(N-1)/2
    Z2: output data structure

    This is the NN-chain algorithm, described on page 86 in the following book:

    Fionn Murtagh, Multidimensional Clustering Algorithms,
    Vienna, Würzburg: Physica-Verlag, 1985.
*/
  t_index i;

  auto_array_ptr<t_index> NN_chain(N);
  t_index NN_chain_tip = 0;

  t_index idx1, idx2;

  t_float size1, size2;
  doubly_linked_list active_nodes(N);

  t_float min;

  for (t_float const * DD=D; DD!=D+(static_cast<std::ptrdiff_t>(N)*(N-1)>>1);
       ++DD) {
#if HAVE_DIAGNOSTIC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
    if (fc_isnan(*DD)) {
      throw(nan_error());
    }
#if HAVE_DIAGNOSTIC
#pragma GCC diagnostic pop
#endif
  }

  #ifdef FE_INVALID
  if (feclearexcept(FE_INVALID)) throw fenv_error();
  #endif

  for (t_index j=0; j<N-1; ++j) {
    if (NN_chain_tip <= 3) {
      NN_chain[0] = idx1 = active_nodes.start;
      NN_chain_tip = 1;

      idx2 = active_nodes.succ[idx1];
      min = D_(idx1,idx2);
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i]) {
        if (D_(idx1,i) < min) {
          min = D_(idx1,i);
          idx2 = i;
        }
      }
    }  // a: idx1   b: idx2
    else {
      NN_chain_tip -= 3;
      idx1 = NN_chain[NN_chain_tip-1];
      idx2 = NN_chain[NN_chain_tip];
      min = idx1<idx2 ? D_(idx1,idx2) : D_(idx2,idx1);
    }  // a: idx1   b: idx2

    do {
      NN_chain[NN_chain_tip] = idx2;

      for (i=active_nodes.start; i<idx2; i=active_nodes.succ[i]) {
        if (D_(i,idx2) < min) {
          min = D_(i,idx2);
          idx1 = i;
        }
      }
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i]) {
        if (D_(idx2,i) < min) {
          min = D_(idx2,i);
          idx1 = i;
        }
      }

      idx2 = idx1;
      idx1 = NN_chain[NN_chain_tip++];

    } while (idx2 != NN_chain[NN_chain_tip-2]);

    Z2.append(idx1, idx2, min);

    if (idx1>idx2) {
      t_index tmp = idx1;
      idx1 = idx2;
      idx2 = tmp;
    }

    if (method==METHOD_METR_AVERAGE ||
        method==METHOD_METR_WARD) {
      size1 = static_cast<t_float>(members[idx1]);
      size2 = static_cast<t_float>(members[idx2]);
      members[idx2] += members[idx1];
    }

    // Remove the smaller index from the valid indices (active_nodes).
    active_nodes.remove(idx1);

    switch (method) {
    case METHOD_METR_SINGLE:
      /*
      Single linkage.

      Characteristic: new distances are never longer than the old distances.
      */
      // Update the distance matrix in the range [start, idx1).
      for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
        f_single(&D_(i, idx2), D_(i, idx1) );
      // Update the distance matrix in the range (idx1, idx2).
      for (; i<idx2; i=active_nodes.succ[i])
        f_single(&D_(i, idx2), D_(idx1, i) );
      // Update the distance matrix in the range (idx2, N).
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
        f_single(&D_(idx2, i), D_(idx1, i) );
      break;

    case METHOD_METR_COMPLETE:
      /*
      Complete linkage.

      Characteristic: new distances are never shorter than the old distances.
      */
      // Update the distance matrix in the range [start, idx1).
      for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
        f_complete(&D_(i, idx2), D_(i, idx1) );
      // Update the distance matrix in the range (idx1, idx2).
      for (; i<idx2; i=active_nodes.succ[i])
        f_complete(&D_(i, idx2), D_(idx1, i) );
      // Update the distance matrix in the range (idx2, N).
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
        f_complete(&D_(idx2, i), D_(idx1, i) );
      break;

    case METHOD_METR_AVERAGE: {
      /*
      Average linkage.

      Shorter and longer distances can occur.
      */
      // Update the distance matrix in the range [start, idx1).
      t_float s = size1/(size1+size2);
      t_float t = size2/(size1+size2);
      for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
        f_average(&D_(i, idx2), D_(i, idx1), s, t );
      // Update the distance matrix in the range (idx1, idx2).
      for (; i<idx2; i=active_nodes.succ[i])
        f_average(&D_(i, idx2), D_(idx1, i), s, t );
      // Update the distance matrix in the range (idx2, N).
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
        f_average(&D_(idx2, i), D_(idx1, i), s, t );
      break;
    }

    case METHOD_METR_WEIGHTED:
      /*
      Weighted linkage.

      Shorter and longer distances can occur.
      */
      // Update the distance matrix in the range [start, idx1).
      for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
        f_weighted(&D_(i, idx2), D_(i, idx1) );
      // Update the distance matrix in the range (idx1, idx2).
      for (; i<idx2; i=active_nodes.succ[i])
        f_weighted(&D_(i, idx2), D_(idx1, i) );
      // Update the distance matrix in the range (idx2, N).
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
        f_weighted(&D_(idx2, i), D_(idx1, i) );
      break;

    case METHOD_METR_WARD:
      /*
      Ward linkage.

      Shorter and longer distances can occur, not smaller than min(d1,d2)
      but maybe bigger than max(d1,d2).
      */
      // Update the distance matrix in the range [start, idx1).
      //t_float v = static_cast<t_float>(members[i]);
      for (i=active_nodes.start; i<idx1; i=active_nodes.succ[i])
        f_ward(&D_(i, idx2), D_(i, idx1), min,
               size1, size2, static_cast<t_float>(members[i]) );
      // Update the distance matrix in the range (idx1, idx2).
      for (; i<idx2; i=active_nodes.succ[i])
        f_ward(&D_(i, idx2), D_(idx1, i), min,
               size1, size2, static_cast<t_float>(members[i]) );
      // Update the distance matrix in the range (idx2, N).
      for (i=active_nodes.succ[idx2]; i<N; i=active_nodes.succ[i])
        f_ward(&D_(idx2, i), D_(idx1, i), min,
               size1, size2, static_cast<t_float>(members[i]) );
      break;

    default:
      throw std::runtime_error(std::string("Invalid method."));
    }
  }
  #ifdef FE_INVALID
  if (fetestexcept(FE_INVALID)) throw fenv_error();
  #endif
}
bool IEEE754ExceptionsPlugin::checkIeee754ExeptionFlag(int flag)
{
    return fetestexcept(flag);
}
示例#14
0
/*
 * Test feholdexcept() and feupdateenv().
 *
 * Prerequisites: fetestexcept(), fegetround(), fesetround(),
 *	fedisableexcept(), feenableexcept()
 */
static void
test_feholdupdate(void)
{
	fenv_t env;

	struct sigaction act;
	int except, i, pass, status, raise;

	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = trap_handler;
	for (pass = 0; pass < 2; pass++) {
		for (i = 0; i < NEXCEPTS; i++) {
			except = std_excepts[i];
			/* over/underflow may also raise inexact */
			if (except == FE_INEXACT)
				raise = FE_DIVBYZERO | FE_INVALID;
			else
				raise = ALL_STD_EXCEPT ^ except;

			/*
			 * We need to fork a child process because
			 * there isn't a portable way to recover from
			 * a floating-point exception.
			 */
			switch(fork()) {
			case 0:		/* child */
				/*
				 * We don't want to cause a fatal exception in
				 * the child until the second pass, so we can
				 * check other properties of feupdateenv().
				 */				
				if (pass == 1)
					assert((feenableexcept(except) &
						   ALL_STD_EXCEPT) == 0);
				raiseexcept(raise);
				assert(fesetround(FE_DOWNWARD) == 0);
				assert(feholdexcept(&env) == 0);
				assert(fetestexcept(FE_ALL_EXCEPT) == 0);
				raiseexcept(except);
				assert(fesetround(FE_UPWARD) == 0);

				if (pass == 1)
					assert(sigaction(SIGFPE, &act, NULL) ==
					    0);
				assert(feupdateenv(&env) == 0);
				assert(fegetround() == FE_DOWNWARD);
				assert(fetestexcept(ALL_STD_EXCEPT) ==
				    (except | raise));

				assert(pass == 0);
				_exit(0);
			default:	/* parent */
				assert(wait(&status) > 0);
				/*
				 * Avoid assert() here so that it's possible
				 * to examine a failed child's core dump.
				 */
				if (!WIFEXITED(status))
					errx(1, "child aborted\n");
				assert(WEXITSTATUS(status) == 0);
				break;
			case -1:	/* error */
				assert(0);
			}
		}
	}
	assert(fetestexcept(FE_ALL_EXCEPT) == 0);
}
示例#15
0
文件: s_fma.c 项目: SylvestreG/bitrig
double
fma(double x, double y, double z)
{
	static const double split = 0x1p27 + 1.0;
	double xs, ys, zs;
	double c, cc, hx, hy, p, q, tx, ty;
	double r, rr, s;
	int oround;
	int ex, ey, ez;
	int spread;

	/*
	 * Handle special cases. The order of operations and the particular
	 * return values here are crucial in handling special cases involving
	 * infinities, NaNs, overflows, and signed zeroes correctly.
	 */
	if (x == 0.0 || y == 0.0)
		return (x * y + z);
	if (z == 0.0)
		return (x * y);
	if (!isfinite(x) || !isfinite(y))
		return (x * y + z);
	if (!isfinite(z))
		return (z);

	xs = frexp(x, &ex);
	ys = frexp(y, &ey);
	zs = frexp(z, &ez);
	oround = fegetround();
	spread = ex + ey - ez;

	/*
	 * If x * y and z are many orders of magnitude apart, the scaling
	 * will overflow, so we handle these cases specially.  Rounding
	 * modes other than FE_TONEAREST are painful.
	 */
	if (spread > DBL_MANT_DIG * 2) {
		fenv_t env;
		feraiseexcept(FE_INEXACT);
		switch(oround) {
		case FE_TONEAREST:
			return (x * y);
		case FE_TOWARDZERO:
			if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0))
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafter(r, 0);
			feupdateenv(&env);
			return (r);
		case FE_DOWNWARD:
			if (z > 0.0)
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafter(r, -INFINITY);
			feupdateenv(&env);
			return (r);
		default:	/* FE_UPWARD */
			if (z < 0.0)
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafter(r, INFINITY);
			feupdateenv(&env);
			return (r);
		}
	}
	if (spread < -DBL_MANT_DIG) {
		feraiseexcept(FE_INEXACT);
		if (!isnormal(z))
			feraiseexcept(FE_UNDERFLOW);
		switch (oround) {
		case FE_TONEAREST:
			return (z);
		case FE_TOWARDZERO:
			if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0))
				return (z);
			else
				return (nextafter(z, 0));
		case FE_DOWNWARD:
			if ((x > 0.0) ^ (y < 0.0))
				return (z);
			else
				return (nextafter(z, -INFINITY));
		default:	/* FE_UPWARD */
			if ((x > 0.0) ^ (y < 0.0))
				return (nextafter(z, INFINITY));
			else
				return (z);
		}
	}

	/*
	 * Use Dekker's algorithm to perform the multiplication and
	 * subsequent addition in twice the machine precision.
	 * Arrange so that x * y = c + cc, and x * y + z = r + rr.
	 */
	fesetround(FE_TONEAREST);

	p = xs * split;
	hx = xs - p;
	hx += p;
	tx = xs - hx;

	p = ys * split;
	hy = ys - p;
	hy += p;
	ty = ys - hy;

	p = hx * hy;
	q = hx * ty + tx * hy;
	c = p + q;
	cc = p - c + q + tx * ty;

	zs = ldexp(zs, -spread);
	r = c + zs;
	s = r - c;
	rr = (c - (r - s)) + (zs - s) + cc;

	spread = ex + ey;
	if (spread + ilogb(r) > -1023) {
		fesetround(oround);
		r = r + rr;
	} else {
		/*
		 * The result is subnormal, so we round before scaling to
		 * avoid double rounding.
		 */
		p = ldexp(copysign(0x1p-1022, r), -spread);
		c = r + p;
		s = c - r;
		cc = (r - (c - s)) + (p - s) + rr;
		fesetround(oround);
		r = (c + cc) - p;
	}
	return (ldexp(r, spread));
}
示例#16
0
/*
 * Fused multiply-add: Compute x * y + z with a single rounding error.
 *
 * We use scaling to avoid overflow/underflow, along with the
 * canonical precision-doubling technique adapted from:
 *
 *	Dekker, T.  A Floating-Point Technique for Extending the
 *	Available Precision.  Numer. Math. 18, 224-242 (1971).
 */
long double
fmal(long double x, long double y, long double z)
{
#if LDBL_MANT_DIG == 64
	static const long double split = 0x1p32L + 1.0;
#elif LDBL_MANT_DIG == 113
	static const long double split = 0x1p57L + 1.0;
#endif
	long double xs, ys, zs;
	long double c, cc, hx, hy, p, q, tx, ty;
	long double r, rr, s;
	int oround;
	int ex, ey, ez;
	int spread;

	if (z == 0.0)
		return (x * y);
	if (x == 0.0 || y == 0.0)
		return (x * y + z);

	/* Results of frexp() are undefined for these cases. */
	if (!isfinite(x) || !isfinite(y) || !isfinite(z))
		return (x * y + z);

	xs = frexpl(x, &ex);
	ys = frexpl(y, &ey);
	zs = frexpl(z, &ez);
	oround = fegetround();
	spread = ex + ey - ez;

	/*
	 * If x * y and z are many orders of magnitude apart, the scaling
	 * will overflow, so we handle these cases specially.  Rounding
	 * modes other than FE_TONEAREST are painful.
	 */
	if (spread > LDBL_MANT_DIG * 2) {
		fenv_t env;
		feraiseexcept(FE_INEXACT);
		switch(oround) {
		case FE_TONEAREST:
			return (x * y);
		case FE_TOWARDZERO:
			if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafterl(r, 0);
			feupdateenv(&env);
			return (r);
		case FE_DOWNWARD:
			if (z > 0.0)
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafterl(r, -INFINITY);
			feupdateenv(&env);
			return (r);
		default:	/* FE_UPWARD */
			if (z < 0.0)
				return (x * y);
			feholdexcept(&env);
			r = x * y;
			if (!fetestexcept(FE_INEXACT))
				r = nextafterl(r, INFINITY);
			feupdateenv(&env);
			return (r);
		}
	}
	if (spread < -LDBL_MANT_DIG) {
		feraiseexcept(FE_INEXACT);
		if (!isnormal(z))
			feraiseexcept(FE_UNDERFLOW);
		switch (oround) {
		case FE_TONEAREST:
			return (z);
		case FE_TOWARDZERO:
			if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
				return (z);
			else
				return (nextafterl(z, 0));
		case FE_DOWNWARD:
			if (x > 0.0 ^ y < 0.0)
				return (z);
			else
				return (nextafterl(z, -INFINITY));
		default:	/* FE_UPWARD */
			if (x > 0.0 ^ y < 0.0)
				return (nextafterl(z, INFINITY));
			else
				return (z);
		}
	}

	/*
	 * Use Dekker's algorithm to perform the multiplication and
	 * subsequent addition in twice the machine precision.
	 * Arrange so that x * y = c + cc, and x * y + z = r + rr.
	 */
	fesetround(FE_TONEAREST);

	p = xs * split;
	hx = xs - p;
	hx += p;
	tx = xs - hx;

	p = ys * split;
	hy = ys - p;
	hy += p;
	ty = ys - hy;

	p = hx * hy;
	q = hx * ty + tx * hy;
	c = p + q;
	cc = p - c + q + tx * ty;

	zs = ldexpl(zs, -spread);
	r = c + zs;
	s = r - c;
	rr = (c - (r - s)) + (zs - s) + cc;

	spread = ex + ey;
	if (spread + ilogbl(r) > -16383) {
		fesetround(oround);
		r = r + rr;
	} else {
		/*
		 * The result is subnormal, so we round before scaling to
		 * avoid double rounding.
		 */
		p = ldexpl(copysignl(0x1p-16382L, r), -spread);
		c = r + p;
		s = c - r;
		cc = (r - (c - s)) + (p - s) + rr;
		fesetround(oround);
		r = (c + cc) - p;
	}
	return (ldexpl(r, spread));
}
bool IEEE754ExceptionsPlugin::checkIeee754UnderflowExceptionFlag()
{
    return fetestexcept(FE_UNDERFLOW) != 0;
}
示例#18
0
DLLEXPORT long double
sqrtl(long double x)
{
	union IEEEl2bits u;
	int k, r;
	long double lo, xn;
	fenv_t env;

	u.e = x;

	/* If x = NaN, then sqrt(x) = NaN. */
	/* If x = Inf, then sqrt(x) = Inf. */
	/* If x = -Inf, then sqrt(x) = NaN. */
	if (u.bits.exp == LDBL_MAX_EXP * 2 - 1)
		return (x * x + x);

	/* If x = +-0, then sqrt(x) = +-0. */
	if ((u.bits.manh | u.bits.manl | u.bits.exp) == 0)
		return (x);

	/* If x < 0, then raise invalid and return NaN */
	if (u.bits.sign)
		return ((x - x) / (x - x));

	feholdexcept(&env);

	if (u.bits.exp == 0) {
		/* Adjust subnormal numbers. */
		u.e *= 0x1.0p514;
		k = -514;
	} else {
		k = 0;
	}
	/*
	 * u.e is a normal number, so break it into u.e = e*2^n where
	 * u.e = (2*e)*2^2k for odd n and u.e = (4*e)*2^2k for even n.
	 */
	if ((u.bits.exp - 0x3ffe) & 1) {	/* n is odd.     */
		k += u.bits.exp - 0x3fff;	/* 2k = n - 1.   */
		u.bits.exp = 0x3fff;		/* u.e in [1,2). */
	} else {
		k += u.bits.exp - 0x4000;	/* 2k = n - 2.   */
		u.bits.exp = 0x4000;		/* u.e in [2,4). */
	}

	/*
	 * Newton's iteration.
	 * Split u.e into a high and low part to achieve additional precision.
	 */
	xn = sqrt(u.e);			/* 53-bit estimate of sqrtl(x). */
#if LDBL_MANT_DIG > 100
	xn = (xn + (u.e / xn)) * 0.5;	/* 106-bit estimate. */
#endif
	lo = u.e;
	u.bits.manl = 0;		/* Zero out lower bits. */
	lo = (lo - u.e) / xn;		/* Low bits divided by xn. */
	xn = xn + (u.e / xn);		/* High portion of estimate. */
	u.e = xn + lo;			/* Combine everything. */
	u.bits.exp += (k >> 1) - 1;

	feclearexcept(FE_INEXACT);
	r = fegetround();
	fesetround(FE_TOWARDZERO);	/* Set to round-toward-zero. */
	xn = x / u.e;			/* Chopped quotient (inexact?). */

	if (!fetestexcept(FE_INEXACT)) { /* Quotient is exact. */
		if (xn == u.e) {
			fesetenv(&env);
			return (u.e);
		}
		/* Round correctly for inputs like x = y**2 - ulp. */
		xn = dec(xn);		/* xn = xn - ulp. */
	}

	if (r == FE_TONEAREST) {
		xn = inc(xn);		/* xn = xn + ulp. */
	} else if (r == FE_UPWARD) {
		u.e = inc(u.e);		/* u.e = u.e + ulp. */
		xn = inc(xn);		/* xn  = xn + ulp. */
	}
	u.e = u.e + xn;				/* Chopped sum. */
	feupdateenv(&env);	/* Restore env and raise inexact */
	u.bits.exp--;
	return (u.e);
}
示例#19
0
int
main(int argc, char *argv[])
{
	char buf[128];
	long double ld = 0.0;
	double d = 0.0;
	float f = 0.0;
	char *endp;

	printf("1..4\n");

	buf[0] = '\0';
	assert(setlocale(LC_NUMERIC, ""));

	/*
	 * Various tests for normalized numbers
	 */
	sscanf("3.141592", "%e", &f);
	assert(eq(FLT, f, 3.141592));

	sscanf("3.141592653589793", "%lf", &d);
	assert(eq(DBL, d, 3.141592653589793));

	sscanf("1.234568e+06", "%E", &f);
	assert(eq(FLT, f, 1.234568e+06));

	sscanf("-1.234568e6", "%lF", &d);
	assert(eq(DBL, d, -1.234568e6));

	sscanf("+1.234568e-52", "%LG", &ld);
	assert(eq(LDBL, ld, 1.234568e-52L));

	sscanf("0.1", "%la", &d);
	assert(eq(DBL, d, 0.1));

	sscanf("00.2", "%lA", &d);
	assert(eq(DBL, d, 0.2));

	sscanf("123456", "%5le%s", &d, buf);
	assert(eq(DBL, d, 12345.));
	assert(strcmp(buf, "6") == 0);

	sscanf("1.0Q", "%*5le%s", buf);
	assert(strcmp(buf, "Q") == 0);

	sscanf("-1.23e", "%e%s", &f, buf);
	assert(eq(FLT, f, -1.23));
	assert(strcmp(buf, "e") == 0);

	sscanf("1.25e+", "%le%s", &d, buf);
	assert(eq(DBL, d, 1.25));
	assert(strcmp(buf, "e+") == 0);

	sscanf("1.23E4E5", "%le%s", &d, buf);
	assert(eq(DBL, d, 1.23e4));
	assert(strcmp(buf, "E5") == 0);

	sscanf("12e6", "%le", &d);
	assert(eq(DBL, d, 12e6));

	sscanf("1.a", "%le%s", &d, buf);
	assert(eq(DBL, d, 1.0));
	assert(strcmp(buf, "a") == 0);

	sscanf(".0p4", "%le%s", &d, buf);
	assert(eq(DBL, d, 0.0));
	assert(strcmp(buf, "p4") == 0);

	d = 0.25;
	assert(sscanf(".", "%le", &d) == 0);
	assert(d == 0.25);

	sscanf("0x08", "%le", &d);
	assert(d == 0x8p0);

	sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf);
	assert(d == 0x90a.bcdefp+09);
	assert(strcmp(buf, "a") == 0);

#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
	sscanf("3.14159265358979323846", "%Lg", &ld);
	assert(eq(LDBL, ld, 3.14159265358979323846L));

	sscanf("  0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf);
	assert(ld == 0x0.0123456789abcdefffp-3L);
	assert(strcmp(buf, "g") == 0);
#endif

	sscanf("0xg", "%le%s", &d, buf);
	assert(d == 0.0);
	assert(strcmp(buf, "xg") == 0);

	assert(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */

	sscanf("1.23", "%le%s", &d, buf);
	assert(d == 1.0);
	assert(strcmp(buf, ".23") == 0);

	sscanf("1,23", "%le", &d);
	assert(d == 1.23);

	assert(setlocale(LC_NUMERIC, ""));

	printf("ok 1 - scanfloat\n");

	/*
	 * Infinity and NaN tests
	 */
	sscanf("-Inf", "%le", &d);
	assert(d < 0.0 && isinf(d));

	sscanf("iNfInItY and beyond", "%le%s", &d, buf);
	assert(d > 0.0 && isinf(d));
	assert(strcmp(buf, " and beyond"));

	sscanf("NaN", "%le", &d);
	assert(isnan(d));

	sscanf("NAN(123Y", "%le%s", &d, buf);
	assert(isnan(d));
	assert(strcmp(buf, "(123Y") == 0);

	sscanf("nan(f00f)plugh", "%le%s", &d, buf);
	assert(isnan(d));
	assert(strcmp(buf, "plugh") == 0);

	sscanf("-nan", "%le", &d);
	assert(isnan(d));

	/* Only quiet NaNs should be returned. */
	sscanf("NaN", "%e", &f);
	sscanf("nan", "%le", &d);
	sscanf("nan", "%Le", &ld);
	feclearexcept(FE_ALL_EXCEPT);
	assert(f != f);
	assert(d != d);
	assert(ld != ld);
	assert(fetestexcept(FE_INVALID) == 0);
	sscanf("nan(1234)", "%e", &f);
	sscanf("nan(1234)", "%le", &d);
	sscanf("nan(1234)", "%Le", &ld);
	feclearexcept(FE_ALL_EXCEPT);
	assert(f != f);
	assert(d != d);
	assert(ld != ld);
	/* POSIX says we should only generate quiet NaNs. */
	assert(fetestexcept(FE_INVALID) == 0);

	printf("ok 2 - scanfloat\n");

	/*
	 * Rounding tests
	 */

	fesetround(FE_DOWNWARD);

	sscanf("1.999999999999999999999999999999999", "%le", &d);
	assert(d < 2.0);
	sscanf("0x1.ffffffffffffffp0", "%le", &d);
	assert(d < 2.0);
	sscanf("1.999999999999999999999999999999999", "%Le", &ld);
	assert(ld < 2.0);

	sscanf("1.0571892669084007", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc59p0);
	sscanf("-1.0571892669084007", "%le", &d);
	assert(d == -0x1.0ea3f4af0dc5ap0);
	sscanf("1.0571892669084010", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc5ap0);

	sscanf("0x1.23p-5000", "%le", &d);
	assert(d == 0.0);

	sscanf("0x1.2345678p-1050", "%le", &d);
	assert(d == 0x1.234567p-1050);

	fesetround(FE_UPWARD);

	sscanf("1.0571892669084007", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc5ap0);
	sscanf("-1.0571892669084007", "%le", &d);
	assert(d == -0x1.0ea3f4af0dc59p0);
	sscanf("1.0571892669084010", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc5bp0);

	sscanf("0x1.23p-5000", "%le", &d);
	assert(d == 0x1p-1074);

	sscanf("0x1.2345678p-1050", "%le", &d);
	assert(d == 0x1.234568p-1050);

	fesetround(FE_TOWARDZERO);

	sscanf("1.0571892669084007", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc59p0);
	sscanf("-1.0571892669084007", "%le", &d);
	assert(d == -0x1.0ea3f4af0dc59p0);
	sscanf("1.0571892669084010", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc5ap0);

	sscanf("0x1.23p-5000", "%le", &d);
	assert(d == 0.0);

	sscanf("0x1.2345678p-1050", "%le", &d);
	assert(d == 0x1.234567p-1050);

	fesetround(FE_TONEAREST);

	/* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */
	sscanf("1.0571892669084007", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc59p0);
	sscanf("-1.0571892669084007", "%le", &d);
	assert(d == -0x1.0ea3f4af0dc59p0);
	sscanf("1.0571892669084010", "%le", &d);
	assert(d == 0x1.0ea3f4af0dc5bp0);

	/* strtod() should round small numbers to 0. */
	sscanf("0x1.23p-5000", "%le", &d);
	assert(d == 0.0);

	/* Extra digits in a denormal shouldn't break anything. */
	sscanf("0x1.2345678p-1050", "%le", &d);
	assert(d == 0x1.234568p-1050);

	printf("ok 3 - scanfloat\n");

	/*
	 * Tests specific to strtod().
	 */

	assert(strtod("0xy", &endp) == 0);
	assert(strcmp("xy", endp) == 0);

	/* This used to cause an infinite loop and round the wrong way. */
	fesetround(FE_DOWNWARD);
	assert(strtof("3.5e38", &endp) == FLT_MAX);
	assert(strtod("2e308", &endp) == DBL_MAX);
	fesetround(FE_UPWARD);
	assert(strtof("3.5e38", &endp) == INFINITY);
	assert(strtod("2e308", &endp) == INFINITY);
	fesetround(FE_TOWARDZERO);
	assert(strtof("3.5e38", &endp) == FLT_MAX);
	assert(strtod("2e308", &endp) == DBL_MAX);
	fesetround(FE_TONEAREST);
	assert(strtof("3.5e38", &endp) == INFINITY);
	assert(strtod("2e308", &endp) == INFINITY);

	printf("ok 4 - scanfloat\n");

	return (0);
}