gecko-dev/ef/Utilities/General/FloatUtils.cpp

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