| #! /bin/sh |
| |
| # $Id: float-auto.sh,v 1.2 2007/08/24 00:55:33 fredette Exp $ |
| |
| # generic/float-auto.sh - automatically generates C code for floating |
| # point conversion functions: |
| |
| # |
| # Copyright (c) 2004 Matt Fredette |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # 3. All advertising materials mentioning features or use of this software |
| # must display the following acknowledgement: |
| # This product includes software developed by Matt Fredette. |
| # 4. The name of the author may not be used to endorse or promote products |
| # derived from this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
| # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| header=false |
| for option |
| do |
| case $option in |
| --header) header=true ;; |
| esac |
| done |
| |
| PROG=`basename $0` |
| cat <<EOF |
| /* automatically generated by $PROG, do not edit! */ |
| |
| EOF |
| if $header; then :; else |
| cat <<EOF |
| #include <tme/common.h> |
| _TME_RCSID("\$Id: float-auto.sh,v 1.2 2007/08/24 00:55:33 fredette Exp $"); |
| |
| /* includes: */ |
| #include <tme/generic/float.h> |
| |
| EOF |
| fi |
| |
| # permute over the builtin types: |
| # |
| for _builtin_type in float double long_double; do |
| |
| # make the builtin type without underscores, and in all caps: |
| # |
| builtin_type=`echo ${_builtin_type} | sed -e 's/_/ /g'` |
| _BUILTIN_TYPE=`echo ${_builtin_type} | tr 'a-z' 'A-Z'` |
| |
| # dispatch on the builtin type to open any protection: |
| # |
| case ${_builtin_type} in |
| long_double) |
| echo ; echo "#ifdef _TME_HAVE_${_BUILTIN_TYPE}" ;; |
| *) ;; |
| esac |
| |
| # if we're generating a header: |
| # |
| if $header; then |
| cat <<EOF |
| |
| /* if possible, this returns a positive or negative infinity |
| ${builtin_type}, otherwise, this returns the ${builtin_type} value |
| closest to that infinity: */ |
| ${builtin_type} tme_float_infinity_${_builtin_type} _TME_P((int)); |
| |
| /* if possible, this returns a negative zero ${builtin_type}. |
| otherwise, this returns the negative ${builtin_type} value closest |
| to zero: */ |
| ${builtin_type} tme_float_negative_zero_${_builtin_type} _TME_P((void)); |
| EOF |
| else |
| cat <<EOF |
| |
| /* if possible, this returns a positive or negative infinity |
| ${builtin_type}, otherwise, this returns the ${builtin_type} value |
| closest to that infinity: */ |
| ${builtin_type} |
| tme_float_infinity_${_builtin_type}(int negative) |
| { |
| static int inf_set_${_builtin_type}; |
| static ${builtin_type} inf_${_builtin_type}[2]; |
| ${builtin_type} inf_test; |
| int negative_i; |
| |
| /* make sure that negative can index the inf_${_builtin_type} array: */ |
| negative = !!negative; |
| |
| /* if the ${builtin_type} infinities have already been set: */ |
| if (__tme_predict_true(inf_set_${_builtin_type})) { |
| return (inf_${_builtin_type}[negative]); |
| } |
| |
| /* the ${builtin_type} infinities will be set now: */ |
| inf_set_${_builtin_type} = TRUE; |
| |
| /* set the positive and negative infinities: */ |
| for (negative_i = 0; negative_i < 2; negative_i++) { |
| |
| /* start with the limit maximum positive value or limit minimum |
| negative value. double this value until either it doesn't |
| change or it isn't closer to the desired infinity, and then |
| use the previous value: */ |
| inf_test = FLOAT_MAX_${_BUILTIN_TYPE}; |
| if (negative_i) { |
| inf_test = -inf_test; |
| } |
| do { |
| memcpy((char *) &inf_${_builtin_type}[negative_i], (char *) &inf_test, sizeof(inf_test)); |
| inf_test *= 2; |
| } while (memcmp((char *) &inf_${_builtin_type}[negative_i], (char *) &inf_test, sizeof(inf_test)) != 0 |
| && (negative_i |
| ? inf_test < inf_${_builtin_type}[negative_i] |
| : inf_test > inf_${_builtin_type}[negative_i])); |
| |
| /* try to generate the actual infinity by dividing one or negative |
| one by zero. if this value is closer to the desired infinity, |
| use it: */ |
| inf_test = (negative_i ? -1.0 : 1.0) / 0.0; |
| if (negative_i |
| ? inf_test < inf_${_builtin_type}[negative_i] |
| : inf_test > inf_${_builtin_type}[negative_i]) { |
| inf_${_builtin_type}[negative_i] = inf_test; |
| } |
| } |
| |
| /* return the desired infinity: */ |
| return (inf_${_builtin_type}[negative]); |
| } |
| |
| /* if possible, this returns a negative zero ${builtin_type}. |
| otherwise, this returns the negative ${builtin_type} value closest |
| to zero: */ |
| ${builtin_type} |
| tme_float_negative_zero_${_builtin_type}(void) |
| { |
| static int nzero_set_${_builtin_type}; |
| static ${builtin_type} nzero_${_builtin_type}; |
| ${builtin_type} constant_pzero; |
| ${builtin_type} constant_nzero; |
| ${builtin_type} nzero_test; |
| |
| /* if the ${builtin_type} negative zero has already been set: */ |
| if (__tme_predict_true(nzero_set_${_builtin_type})) { |
| return (nzero_${_builtin_type}); |
| } |
| |
| /* the ${builtin_type} negative zero will be set now: */ |
| nzero_set_${_builtin_type} = TRUE; |
| |
| /* make a +0.0 and a -0.0, that we can do bit-for-bit comparisons with. |
| NB that sizeof(${builtin_type}) may cover more bits than are actually |
| used by a ${builtin_type}: */ |
| memset((char *) &constant_pzero, 0, sizeof(constant_pzero)); |
| memset((char *) &constant_nzero, 0, sizeof(constant_nzero)); |
| constant_pzero = +0.0; |
| constant_nzero = -0.0; |
| |
| /* if -0.0 * -0.0 is bit-for-bit different from -0.0 and is |
| bit-for-bit identical to +0.0, use -0.0: */ |
| memset((char *) &nzero_test, 0, sizeof(nzero_test)); |
| nzero_test = constant_nzero * constant_nzero; |
| if (memcmp((char *) &constant_nzero, (char *) &nzero_test, sizeof(nzero_test)) != 0 |
| && memcmp((char *) &constant_pzero, (char *) &nzero_test, sizeof(nzero_test)) == 0) { |
| return (nzero_${_builtin_type} = constant_nzero); |
| } |
| |
| /* otherwise, start with the limit maximum negative value (which is |
| zero minus the limit minimum positive value). halve this value |
| until either it doesn't change or it becomes positive zero, and |
| then use the previous value: */ |
| nzero_test = 0 - FLOAT_MIN_${_BUILTIN_TYPE}; |
| do { |
| memcpy((char *) &nzero_${_builtin_type}, (char *) &nzero_test, sizeof(nzero_test)); |
| nzero_test = nzero_test / 2; |
| } while (memcmp((char *) &nzero_${_builtin_type}, (char *) &nzero_test, sizeof(nzero_test)) != 0 |
| && memcmp((char *) &constant_pzero, (char *) &nzero_test, sizeof(nzero_test)) != 0); |
| return (nzero_${_builtin_type}); |
| } |
| EOF |
| fi |
| |
| |
| # permute over the radices: |
| # |
| for radix in 2 10; do |
| |
| # if we're generating a header: |
| # |
| if $header; then |
| cat <<EOF |
| |
| /* this returns the radix ${radix} mantissa and exponent of an in-range ${builtin_type}. |
| the mantissa is either zero, or in the range [1,${radix}): */ |
| ${builtin_type} tme_float_radix${radix}_mantissa_exponent_${_builtin_type} _TME_P((${builtin_type}, tme_int32_t *)); |
| |
| /* this scales a value by adding n to its radix ${radix} exponent: */ |
| ${builtin_type} tme_float_radix${radix}_scale_${_builtin_type} _TME_P((${builtin_type}, tme_int32_t)); |
| EOF |
| continue |
| fi |
| |
| # permute over the sign of the exponent: |
| # |
| for _sign in pos neg; do |
| |
| # make the sign into two operators: |
| # |
| if test ${_sign} = pos; then sign= ; combine='*' ; else sign=- ; combine='/' ; fi |
| |
| echo "" |
| echo "/* a series of ${builtin_type} values of the form ${radix}^${sign}x, where x is a power of two: */" |
| echo "static const ${builtin_type} _tme_float_radix${radix}_exponent_bits_${_builtin_type}_${_sign}[] = {" |
| exponent=1 |
| formats_last= |
| |
| while true; do |
| |
| # dispatch on the radix to get the largest factor we will |
| # use, its exponent, and a coarse upper bound on this |
| # value's exponent in the worst-case radix of two: |
| # |
| case ${radix} in |
| 2) exponent_radix2=${exponent} ; x=16777216 ; exponent_x=24 ;; |
| 10) exponent_radix2=`expr ${exponent} \* 4` ; x=10000 ; exponent_x=4 ;; |
| *) |
| echo "$PROG internal error: can't handle radix ${radix}" 1>&2 |
| exit 1 |
| ;; |
| esac |
| |
| # we assume that all floating-point formats that use a |
| # radix of two support at least positive and negative |
| # exponents of magnitude 16. if this exponent's |
| # magnitude is greater than that, dispatch to get the |
| # list of floating-point formats that support it: |
| # |
| formats= |
| if test `expr ${exponent_radix2} \> 16` != 0; then |
| |
| # the IEEE 754 types: |
| # |
| if test `expr ${exponent_radix2} \< 16384` != 0; then |
| formats="${formats} | TME_FLOAT_FORMAT_IEEE754_EXTENDED80" |
| fi |
| if test `expr ${exponent_radix2} \< 1024` != 0; then |
| formats="${formats} | TME_FLOAT_FORMAT_IEEE754_DOUBLE" |
| fi |
| if test `expr ${exponent_radix2} \< 128` != 0; then |
| formats="${formats} | TME_FLOAT_FORMAT_IEEE754_SINGLE" |
| fi |
| |
| # if we don't know any formats that support this |
| # exponent, stop now: |
| # |
| if test "x${formats}" = x; then |
| break |
| fi |
| |
| # clean up the formats: |
| # |
| formats="((TME_FLOAT_FORMAT_${_BUILTIN_TYPE} & ("`echo "${formats}" | sed -e 's%^ | %%'`")) != 0)" |
| fi |
| |
| # if the formats have changed: |
| # |
| if test "x${formats}" != "x${formats_last}"; then |
| |
| # close any old #if first: |
| # |
| if test "x${formats_last}" != x; then |
| echo "" |
| echo "#endif /* ${formats_last} */" |
| fi |
| |
| # open the new #if: |
| # |
| echo "" |
| echo "#if ${formats}" |
| formats_last=${formats} |
| fi |
| |
| # compute this value: |
| # |
| echo "" |
| echo " /* ${radix}^${sign}${exponent}: */" |
| exponent_remaining=${exponent} |
| value=1 |
| while test ${exponent_remaining} != 0; do |
| if test `expr ${exponent_remaining} \>= ${exponent_x}` = 1; then |
| value="(${value} ${combine} ((${builtin_type}) ((tme_uint32_t) ${x})))" |
| exponent_remaining=`expr ${exponent_remaining} - ${exponent_x}` |
| else |
| x=`expr ${x} / ${radix}` |
| exponent_x=`expr ${exponent_x} - 1` |
| fi |
| done |
| echo " ${value}," |
| |
| # double the exponent: |
| # |
| exponent=`expr ${exponent} \* 2` |
| done |
| |
| # close any #if: |
| # |
| if test "x${formats_last}" != x; then |
| echo "" |
| echo "#endif /* ${formats_last} */" |
| fi |
| |
| echo "};" |
| done |
| |
| cat <<EOF |
| |
| /* this returns the radix ${radix} mantissa and exponent of an in-range ${builtin_type}. |
| the mantissa is either zero, or in the range [1,${radix}): */ |
| ${builtin_type} |
| tme_float_radix${radix}_mantissa_exponent_${_builtin_type}(${builtin_type} value, tme_int32_t *_exponent) |
| { |
| tme_int32_t exponent; |
| tme_uint32_t exponent_bit; |
| int negate; |
| |
| /* start with an exponent of zero: */ |
| exponent = 0; |
| |
| /* if the value is positive or negative zero, return the value: */ |
| if (value == 0.0 |
| || -value == 0.0) { |
| *_exponent = exponent; |
| return (value); |
| } |
| |
| /* take the magnitude of the value, but remember if it was negative: */ |
| negate = (value < 0); |
| if (negate) { |
| value = 0 - value; |
| } |
| |
| /* while the value is less than one: */ |
| exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg) - 1; |
| for (; value < 1; ) { |
| |
| /* if value is less than or equal to ${radix}^-(2^exponent_bit), |
| divide value by ${radix}^-(2^exponent_bit), and subtract 2^exponent_bit |
| from exponent: */ |
| if (value <= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg[exponent_bit] |
| || exponent_bit == 0) { |
| value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg[exponent_bit]; |
| exponent -= (1 << exponent_bit); |
| } |
| |
| /* otherwise, move to the next exponent bit: */ |
| else { |
| exponent_bit--; |
| } |
| } |
| |
| /* while the value is greater than or equal to ${radix}: */ |
| exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos) - 1; |
| for (; value >= ${radix}; ) { |
| |
| /* if value is greater than or equal to ${radix}^(2^exponent_bit), |
| divide value by ${radix}^(2^exponent_bit), and add 2^exponent_bit |
| to exponent: */ |
| if (value >= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit] |
| || exponent_bit == 0) { |
| value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit]; |
| exponent += (1 << exponent_bit); |
| } |
| |
| /* otherwise, move to the next exponent bit: */ |
| else { |
| exponent_bit--; |
| } |
| } |
| |
| /* done: */ |
| *_exponent = exponent; |
| return (negate ? 0 - value : value); |
| } |
| |
| /* this scales a value by adding n to its exponent: */ |
| ${builtin_type} |
| tme_float_radix${radix}_scale_${_builtin_type}(${builtin_type} value, tme_int32_t _n) |
| { |
| tme_uint32_t exponent_bit, exponent; |
| tme_uint32_t n; |
| |
| /* start with the most significant exponent bit: */ |
| exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos) - 1; |
| exponent = (1 << exponent_bit); |
| |
| /* if n is negative: */ |
| if (_n < 0) { |
| |
| for (n = 0 - _n; n > 0;) { |
| if (n >= exponent || exponent == 1) { |
| value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit]; |
| n -= exponent; |
| } |
| else { |
| exponent >>= 1; |
| exponent_bit--; |
| } |
| } |
| } |
| |
| /* otherwise, n is positive: */ |
| else { |
| for (n = _n; n > 0;) { |
| if (n >= exponent || exponent == 1) { |
| value *= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit]; |
| n -= exponent; |
| } |
| else { |
| exponent >>= 1; |
| exponent_bit--; |
| } |
| } |
| } |
| |
| return (value); |
| } |
| EOF |
| done |
| |
| # dispatch on the type to close any protection: |
| # |
| case ${_builtin_type} in |
| long_double) |
| echo ; echo "#endif /* _TME_HAVE_${_BUILTIN_TYPE} */" ;; |
| *) ;; |
| esac |
| |
| done |
| |
| # done: |
| # |
| exit 0 |