/* * Copyright (C) 2016 The Android Open Source Project * * 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 "floatRt.h" #include <stdbool.h> #include <stdio.h> /* * FLOAT: * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm * * s = negative * e = exponent * m = mantissa (with one bit removed) * * if (e == 0xFF) * if (f) val = inf * else val = nan * goto valDone * else if (e == 0x00) * useLeadingOne = 0 * e = -126 * else * e = e - 127 * useLeadingOne = 1 * * val = ((useLeadingOne << 24) + m) / (2 ^ 23) * val *= 2 ^ e * * valDone: * * if (s) * val = -val; */ #define BIT_SIGN 0x80000000UL #define MANTISSA_BITS 23 #define EXP_SHIFT MANTISSA_BITS #define EXP_ADJUST 127 #ifdef USE_NANOHUB_FLOAT_RUNTIME uint64_t floatToUint64(float f) { uint32_t e, word = *(const uint32_t*)&f; uint64_t ret; //all negatives become zero if (word & BIT_SIGN) return 0; //all values with exponent < 0 are less than one and thus become zero if (word < (EXP_ADJUST << EXP_SHIFT)) return 0; //standard does not say what happens to NaNs, infs & other too-large values, we return a large value as an approximation (though a zero would be equally valid) if (word >= (EXP_ADJUST + 64) << EXP_SHIFT) return 0xFFFFFFFFFFFFFFFFULL; //get mantissa and the implied leading one ret = (word & ((1 << MANTISSA_BITS) - 1)) | (1 << MANTISSA_BITS); e = ((word >> EXP_SHIFT) - EXP_ADJUST); //shift it by the exp if (e < MANTISSA_BITS) ret >>= MANTISSA_BITS - e; else ret <<= e - MANTISSA_BITS; return ret; } int64_t floatToInt64(float f) { uint32_t e, word = *(const uint32_t*)&f; bool neg = (word & BIT_SIGN); uint64_t ret; //all negatives become positive for now word &=~ BIT_SIGN; //all values with exponent < 0 are less than one and thus become zero if (word < (EXP_ADJUST << EXP_SHIFT)) return 0; //standard does not say what happens to NaNs, infs & other too-large values, we return a large value as an approximation (though a zero would be equally valid) if (word >= (EXP_ADJUST + 63) << EXP_SHIFT) ret = 0x7FFFFFFFFFFFFFFFULL; else { //get mantissa and the implied leading one ret = (word & ((1 << MANTISSA_BITS) - 1)) | (1 << MANTISSA_BITS); e = ((word >> EXP_SHIFT) - EXP_ADJUST); //shift it by the exp if (e < MANTISSA_BITS) ret >>= MANTISSA_BITS - e; else ret <<= e - MANTISSA_BITS; } if (neg) ret = -ret; return ret; } float floatFromUint64(uint64_t v) { uint32_t hi = v >> 32, lo = v; if (!hi) //this is very fast for cases where we fit into a uint32_t return(float)lo; else { return ((float)hi) * 4294967296.0f + (float)lo; } } float floatFromInt64(int64_t v) { uint32_t hi = ((uint64_t)v) >> 32, lo = v; if ((hi == 0x00000000 && !(lo >> 31)) || (hi == 0xffffffff && (lo >> 31))) //this complex test is a lot faster then the simpler ((v >> 33) == -1 || (v >> 33) == 0) return (float)(int32_t)lo; else if (hi >> 31) //the case of 0x8000000000000000 is handled here, as negated it remains the same return -floatFromUint64(-v); else return floatFromUint64(v); } #endif // USE_NANOHUB_FLOAT_RUNTIME