зеркало из https://github.com/mozilla/gecko-dev.git
248 строки
6.0 KiB
C++
248 строки
6.0 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include "FloatUtils.h"
|
|
#include <math.h> // For fmod()
|
|
|
|
#ifdef WIN32
|
|
#include <limits>
|
|
Flt32 floatPositiveInfinity;
|
|
Flt64 doublePositiveInfinity;
|
|
Flt32 floatNegativeInfinity;
|
|
Flt64 doubleNegativeInfinity;
|
|
Flt32 floatNegativeZero;
|
|
Flt64 doubleNegativeZero;
|
|
Flt32 floatNaN;
|
|
Flt64 doubleNaN;
|
|
|
|
struct DummyInit
|
|
{
|
|
DummyInit(Flt32 fZero, Flt64 dZero);
|
|
};
|
|
|
|
DummyInit dummyFloatInit(0.0f, 0.0);
|
|
|
|
DummyInit::DummyInit(Flt32, Flt64)
|
|
{
|
|
floatPositiveInfinity = std::numeric_limits<Flt32>::infinity();
|
|
doublePositiveInfinity = std::numeric_limits<Flt64>::infinity();
|
|
floatNegativeInfinity = -std::numeric_limits<Flt32>::infinity();
|
|
doubleNegativeInfinity = -std::numeric_limits<Flt64>::infinity();
|
|
floatNegativeZero = -1.0f/floatPositiveInfinity;
|
|
doubleNegativeZero = -1.0/doublePositiveInfinity;
|
|
floatNaN = std::numeric_limits<Flt32>::quiet_NaN();
|
|
doubleNaN = std::numeric_limits<Flt64>::quiet_NaN();
|
|
}
|
|
|
|
#elif defined __GNUC__
|
|
Flt32 floatPositiveInfinity;
|
|
Flt64 doublePositiveInfinity;
|
|
Flt32 floatNegativeInfinity;
|
|
Flt64 doubleNegativeInfinity;
|
|
Flt32 floatNaN;
|
|
Flt64 doubleNaN;
|
|
|
|
#ifdef IS_LITTLE_ENDIAN
|
|
#define DOUBLE_HI32(x) (((uint32 *)&(x))[1])
|
|
#define DOUBLE_LO32(x) (((uint32 *)&(x))[0])
|
|
#else
|
|
#define DOUBLE_HI32(x) (((uint32 *)&(x))[0])
|
|
#define DOUBLE_LO32(x) (((uint32 *)&(x))[1])
|
|
#endif
|
|
#define DOUBLE_HI32_SIGNBIT 0x80000000
|
|
#define DOUBLE_HI32_EXPMASK 0x7ff00000
|
|
#define DOUBLE_HI32_MANTMASK 0x000fffff
|
|
|
|
union dpun {
|
|
struct {
|
|
#ifdef IS_LITTLE_ENDIAN
|
|
uint32 lo, hi;
|
|
#else
|
|
uint32 hi, lo;
|
|
#endif
|
|
} s;
|
|
Flt64 d;
|
|
};
|
|
|
|
union spun {
|
|
uint32 s;
|
|
Flt32 f;
|
|
};
|
|
|
|
struct DummyInit
|
|
{
|
|
DummyInit() {
|
|
union dpun du;
|
|
union spun su;
|
|
|
|
su.s = 0x7f800000;
|
|
floatPositiveInfinity = su.f;
|
|
|
|
du.s.hi = DOUBLE_HI32_EXPMASK;
|
|
du.s.lo = 0x00000000;
|
|
doublePositiveInfinity = du.d;
|
|
|
|
su.s = 0xff800000;
|
|
floatNegativeInfinity = su.f;
|
|
|
|
du.s.hi = DOUBLE_HI32_SIGNBIT | DOUBLE_HI32_EXPMASK;
|
|
du.s.lo = 0x00000000;
|
|
doubleNegativeInfinity = du.d;
|
|
|
|
su.s = 0x7fc00000;
|
|
floatNaN = su.f;
|
|
|
|
du.s.hi = DOUBLE_HI32_EXPMASK | DOUBLE_HI32_MANTMASK;
|
|
du.s.lo = 0xffffffff;
|
|
doubleNaN = du.d;
|
|
}
|
|
};
|
|
|
|
DummyInit dummyFloatInit;
|
|
|
|
#endif
|
|
|
|
// Wrapper around fmod() is necessary because some implementations doesn't
|
|
// handle infinities properly, e.g. MSVC.
|
|
double javaFMod(double dividend, double divisor) {
|
|
if (isNaN(dividend) || isNaN(divisor) || isInfinite(dividend) || (divisor == 0.0))
|
|
return doubleNaN;
|
|
|
|
if ((dividend == 0.0) || isInfinite(divisor))
|
|
return dividend;
|
|
|
|
return fmod(dividend, divisor);
|
|
}
|
|
|
|
Int32 flt64ToInt32(Flt64 d)
|
|
{
|
|
if (isNaN(d))
|
|
return 0;
|
|
if (d >= (Flt64)(Int32)0x7fffffff)
|
|
return 0x7fffffff;
|
|
if (d <= (Flt64)(Int32)0x80000000)
|
|
return 0x80000000;
|
|
return (Int32)d;
|
|
}
|
|
|
|
Int64 flt64ToInt64(Flt64 d)
|
|
{
|
|
if (isNaN(d))
|
|
return CONST64(0);
|
|
if (d >= (Flt64)CONST64(0x7fffffffffffffff))
|
|
return CONST64(0x7fffffffffffffff);
|
|
if (d <= (Flt64)CONST64(0x8000000000000000))
|
|
return CONST64(0x8000000000000000);
|
|
return (Int64)d;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
template <class T>
|
|
void testFloat(T myNaN, T myNegZero, T myPosInf, T myNegInf)
|
|
{
|
|
T plusZero = 0.0;
|
|
T minusZero = myNegZero;
|
|
T plusOne = 1.0;
|
|
T plusInf = plusOne/plusZero;
|
|
T minusInf = plusOne/minusZero;
|
|
T nan = plusInf + minusInf;
|
|
|
|
assert(plusZero == minusZero);
|
|
assert(plusZero != plusOne);
|
|
assert(plusInf > 0.0);
|
|
assert(minusInf < 0.0);
|
|
assert(!(nan == 0.0));
|
|
assert(!(nan == nan));
|
|
assert(!(nan < nan));
|
|
assert(!(nan > nan));
|
|
assert(!(myNaN == 0.0));
|
|
assert(!(myNaN == myNaN));
|
|
assert(!(myNaN < myNaN));
|
|
assert(!(myNaN > myNaN));
|
|
assert(plusInf == myPosInf);
|
|
assert(minusInf == myNegInf);
|
|
|
|
assert(isPositiveZero(plusZero));
|
|
assert(!isNegativeZero(plusZero));
|
|
assert(!isNaN(plusZero));
|
|
assert(!isPositiveZero(minusZero));
|
|
assert(isNegativeZero(minusZero));
|
|
assert(!isNaN(minusZero));
|
|
assert(!isPositiveZero(plusOne));
|
|
assert(!isNegativeZero(plusOne));
|
|
assert(!isNaN(plusOne));
|
|
assert(!isPositiveZero(plusInf));
|
|
assert(!isNegativeZero(plusInf));
|
|
assert(!isNaN(plusInf));
|
|
assert(!isPositiveZero(minusInf));
|
|
assert(!isNegativeZero(minusInf));
|
|
assert(!isNaN(minusInf));
|
|
assert(!isPositiveZero(nan));
|
|
assert(!isNegativeZero(nan));
|
|
assert(isNaN(nan));
|
|
assert(!isPositiveZero(myNaN));
|
|
assert(!isNegativeZero(myNaN));
|
|
assert(isNaN(myNaN));
|
|
|
|
assert(isPositiveZero(plusZero + minusZero));
|
|
assert(!isNegativeZero(plusZero + minusZero));
|
|
assert(!isNaN(plusZero + minusZero));
|
|
}
|
|
|
|
|
|
static bool testGt(double a, double b)
|
|
{
|
|
return a>b;
|
|
}
|
|
|
|
static bool testGe(double a, double b)
|
|
{
|
|
return a>=b;
|
|
}
|
|
|
|
static bool testLt(double a, double b)
|
|
{
|
|
return a<b;
|
|
}
|
|
|
|
static bool testLe(double a, double b)
|
|
{
|
|
return a<=b;
|
|
}
|
|
|
|
//
|
|
// Test the definitions in FloatUtils.h.
|
|
//
|
|
void testFloatUtils()
|
|
{
|
|
assert(!testGt(doubleNaN, doubleNaN));
|
|
assert(!testGe(doubleNaN, doubleNaN));
|
|
assert(!testLt(doubleNaN, doubleNaN));
|
|
assert(!testLe(doubleNaN, doubleNaN));
|
|
assert(!(doubleNaN > doubleNaN));
|
|
assert(!(doubleNaN >= doubleNaN));
|
|
assert(doubleNaN != doubleNaN);
|
|
testFloat(floatNaN, floatNegativeZero, floatPositiveInfinity, floatNegativeInfinity);
|
|
testFloat(doubleNaN, doubleNegativeZero, doublePositiveInfinity, doubleNegativeInfinity);
|
|
}
|
|
#endif
|