diff options
Diffstat (limited to 'skia/corecg/SkFloat.cpp')
-rw-r--r-- | skia/corecg/SkFloat.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/skia/corecg/SkFloat.cpp b/skia/corecg/SkFloat.cpp new file mode 100644 index 0000000..bb96947 --- /dev/null +++ b/skia/corecg/SkFloat.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2006-2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SkFloat.h" +#include "SkMath.h" + +#define EXP_BIAS (127+23) + +static int get_unsigned_exp(uint32_t packed) +{ + return (packed << 1 >> 24); +} + +static unsigned get_unsigned_value(uint32_t packed) +{ + return (packed << 9 >> 9) | (1 << 23); +} + +static int get_signed_value(int32_t packed) +{ + return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed)); +} + +///////////////////////////////////////////////////////////////////////// + +int SkFloat::GetShift(int32_t packed, int shift) +{ + if (packed == 0) + return 0; + + int exp = get_unsigned_exp(packed) - EXP_BIAS - shift; + int value = get_unsigned_value(packed); + + if (exp >= 0) + { + if (exp > 8) // overflow + value = SK_MaxS32; + else + value <<= exp; + } + else + { + exp = -exp; + if (exp > 23) // underflow + value = 0; + else + value >>= exp; + } + return SkApplySign(value, SkExtractSign(packed)); +} + +///////////////////////////////////////////////////////////////////////////////////// + +int32_t SkFloat::SetShift(int value, int shift) +{ + if (value == 0) + return 0; + + // record the sign and make value positive + int sign = SkExtractSign(value); + value = SkApplySign(value, sign); + + if (value >> 24) // value is too big (has more than 24 bits set) + { + int bias = 8 - SkCLZ(value); + SkASSERT(bias > 0 && bias < 8); + value >>= bias; + shift += bias; + } + else + { + int zeros = SkCLZ(value << 8); + SkASSERT(zeros >= 0 && zeros <= 23); + value <<= zeros; + shift -= zeros; + } + // now value is left-aligned to 24 bits + SkASSERT((value >> 23) == 1); + + shift += EXP_BIAS; + if (shift < 0) // underflow + return 0; + else + { + if (shift > 255) // overflow + { + shift = 255; + value = 0x00FFFFFF; + } + int32_t packed = sign << 31; // set the sign-bit + packed |= shift << 23; // store the packed exponent + packed |= ((unsigned)(value << 9) >> 9); // clear 24th bit of value (its implied) + +#ifdef SK_DEBUG + { + int n; + + n = SkExtractSign(packed); + SkASSERT(n == sign); + n = get_unsigned_exp(packed); + SkASSERT(n == shift); + n = get_unsigned_value(packed); + SkASSERT(n == value); + } +#endif + return packed; + } +} + +int32_t SkFloat::Neg(int32_t packed) +{ + if (packed) + packed = packed ^ (1 << 31); + return packed; +} + +int32_t SkFloat::Add(int32_t packed_a, int32_t packed_b) +{ + if (packed_a == 0) + return packed_b; + if (packed_b == 0) + return packed_a; + + int exp_a = get_unsigned_exp(packed_a); + int exp_b = get_unsigned_exp(packed_b); + int exp_diff = exp_a - exp_b; + + int shift_a = 0, shift_b = 0; + int exp; + + if (exp_diff >= 0) + { + if (exp_diff > 24) // B is too small to contribute + return packed_a; + shift_b = exp_diff; + exp = exp_a; + } + else + { + exp_diff = -exp_diff; + if (exp_diff > 24) // A is too small to contribute + return packed_b; + shift_a = exp_diff; + exp = exp_b; + } + + int value_a = get_signed_value(packed_a) >> shift_a; + int value_b = get_signed_value(packed_b) >> shift_b; + + return SkFloat::SetShift(value_a + value_b, exp - EXP_BIAS); +} + +#include "Sk64.h" + +static inline int32_t mul24(int32_t a, int32_t b) +{ + Sk64 tmp; + + tmp.setMul(a, b); + tmp.roundRight(24); + return tmp.get32(); +} + +int32_t SkFloat::Mul(int32_t packed_a, int32_t packed_b) +{ + if (packed_a == 0 || packed_b == 0) + return 0; + + int exp_a = get_unsigned_exp(packed_a); + int exp_b = get_unsigned_exp(packed_b); + + int value_a = get_signed_value(packed_a); + int value_b = get_signed_value(packed_b); + + return SkFloat::SetShift(mul24(value_a, value_b), exp_a + exp_b - 2*EXP_BIAS + 24); +} + +int32_t SkFloat::MulInt(int32_t packed, int n) +{ + return Mul(packed, SetShift(n, 0)); +} + +int32_t SkFloat::Div(int32_t packed_n, int32_t packed_d) +{ + SkASSERT(packed_d != 0); + + if (packed_n == 0) + return 0; + + int exp_n = get_unsigned_exp(packed_n); + int exp_d = get_unsigned_exp(packed_d); + + int value_n = get_signed_value(packed_n); + int value_d = get_signed_value(packed_d); + + return SkFloat::SetShift(SkDivBits(value_n, value_d, 24), exp_n - exp_d - 24); +} + +int32_t SkFloat::DivInt(int32_t packed, int n) +{ + return Div(packed, SetShift(n, 0)); +} + +int32_t SkFloat::Invert(int32_t packed) +{ + return Div(packed, SetShift(1, 0)); +} + +int32_t SkFloat::Sqrt(int32_t packed) +{ + if (packed < 0) + { + SkASSERT(!"can't sqrt a negative number"); + return 0; + } + + int exp = get_unsigned_exp(packed); + int value = get_unsigned_value(packed); + + int nexp = exp - EXP_BIAS; + int root = SkSqrtBits(value << (nexp & 1), 26); + nexp >>= 1; + return SkFloat::SetShift(root, nexp - 11); +} + +#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : unreachable code +#pragma warning ( push ) +#pragma warning ( disable : 4702 ) +#endif + +int32_t SkFloat::CubeRoot(int32_t packed) +{ + sk_throw(); + return 0; +} + +#if defined _WIN32 && _MSC_VER >= 1300 +#pragma warning ( pop ) +#endif + +static inline int32_t clear_high_bit(int32_t n) +{ + return ((uint32_t)(n << 1)) >> 1; +} + +static inline int int_sign(int32_t a, int32_t b) +{ + return a > b ? 1 : (a < b ? -1 : 0); +} + +int SkFloat::Cmp(int32_t packed_a, int32_t packed_b) +{ + packed_a = SkApplySign(clear_high_bit(packed_a), SkExtractSign(packed_a)); + packed_b = SkApplySign(clear_high_bit(packed_b), SkExtractSign(packed_b)); + + return int_sign(packed_a, packed_b); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +#include "SkRandom.h" +#ifdef SK_CAN_USE_FLOAT + #include "SkFloatingPoint.h" +#endif + +void SkFloat::UnitTest() +{ +#ifdef SK_SUPPORT_UNITTEST + SkFloat a, b, c, d; + int n; + + a.setZero(); + n = a.getInt(); + SkASSERT(n == 0); + + b.setInt(5); + n = b.getInt(); + SkASSERT(n == 5); + + c.setInt(-3); + n = c.getInt(); + SkASSERT(n == -3); + + d.setAdd(c, b); + SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt()); + + SkRandom rand; + +#ifdef SK_CAN_USE_FLOAT + int i; + for (i = 0; i < 1000; i++) + { + float fa, fb; + int aa = rand.nextS() >> 14; + int bb = rand.nextS() >> 14; + a.setInt(aa); + b.setInt(bb); + SkASSERT(a.getInt() == aa); + SkASSERT(b.getInt() == bb); + + c.setAdd(a, b); + int cc = c.getInt(); + SkASSERT(cc == aa + bb); + + c.setSub(a, b); + cc = c.getInt(); + SkASSERT(cc == aa - bb); + + aa >>= 5; + bb >>= 5; + a.setInt(aa); + b.setInt(bb); + c.setMul(a, b); + cc = c.getInt(); + SkASSERT(cc == aa * bb); + ///////////////////////////////////// + + aa = rand.nextS() >> 11; + a.setFixed(aa); + cc = a.getFixed(); + SkASSERT(aa == cc); + + bb = rand.nextS() >> 11; + b.setFixed(bb); + cc = b.getFixed(); + SkASSERT(bb == cc); + + cc = SkFixedMul(aa, bb); + c.setMul(a, b); + SkFixed dd = c.getFixed(); + int diff = cc - dd; + SkASSERT(SkAbs32(diff) <= 1); + + fa = (float)aa / 65536.0f; + fb = (float)bb / 65536.0f; + a.assertEquals(fa); + b.assertEquals(fb); + fa = a.getFloat(); + fb = b.getFloat(); + + c.assertEquals(fa * fb, 1); + + c.setDiv(a, b); + cc = SkFixedDiv(aa, bb); + dd = c.getFixed(); + diff = cc - dd; + SkASSERT(SkAbs32(diff) <= 3); + + c.assertEquals(fa / fb, 1); + + SkASSERT((aa == bb) == (a == b)); + SkASSERT((aa != bb) == (a != b)); + SkASSERT((aa < bb) == (a < b)); + SkASSERT((aa <= bb) == (a <= b)); + SkASSERT((aa > bb) == (a > b)); + SkASSERT((aa >= bb) == (a >= b)); + + if (aa < 0) + { + aa = -aa; + fa = -fa; + } + a.setFixed(aa); + c.setSqrt(a); + cc = SkFixedSqrt(aa); + dd = c.getFixed(); + SkASSERT(dd == cc); + + c.assertEquals(sk_float_sqrt(fa), 2); + + // cuberoot +#if 0 + a.setInt(1); + a.cubeRoot(); + a.assertEquals(1.0f, 0); + a.setInt(8); + a.cubeRoot(); + a.assertEquals(2.0f, 0); + a.setInt(27); + a.cubeRoot(); + a.assertEquals(3.0f, 0); +#endif + } +#endif +#endif +} + +#endif |