Blame converter/other/fiasco/lib/rpf.c

Packit 78deda
/*
Packit 78deda
 *  rpf.c:      Conversion of float to reduced precision format values
Packit 78deda
 *
Packit 78deda
 *  Written by:     Stefan Frank
Packit 78deda
 *          Richard Krampfl
Packit 78deda
 *          Ullrich Hafner
Packit 78deda
 *      
Packit 78deda
 *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
Packit 78deda
 *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
Packit 78deda
 */
Packit 78deda
Packit 78deda
/*
Packit 78deda
 *  $Date: 2000/06/14 20:49:37 $
Packit 78deda
 *  $Author: hafner $
Packit 78deda
 *  $Revision: 5.1 $
Packit 78deda
 *  $State: Exp $
Packit 78deda
 */
Packit 78deda
Packit 78deda
#include "pm_config.h"
Packit 78deda
#include "config.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
Packit 78deda
#include "types.h"
Packit 78deda
#include "macros.h"
Packit 78deda
#include "error.h"
Packit 78deda
Packit 78deda
#include "misc.h"
Packit 78deda
#include "rpf.h"
Packit 78deda
Packit 78deda
int const RPF_ZERO = -1;
Packit 78deda
Packit 78deda
/*****************************************************************************
Packit 78deda
Packit 78deda
                   private code
Packit 78deda
  
Packit 78deda
*****************************************************************************/
Packit 78deda
Packit 78deda
Packit 78deda
typedef struct {
Packit 78deda
    double fraction;
Packit 78deda
    int    exponent;
Packit 78deda
}  FracExp;
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static FracExp
Packit 78deda
fracExpFromDouble(double const x) {
Packit 78deda
Packit 78deda
    FracExp retval;
Packit 78deda
Packit 78deda
    retval.fraction = frexp(x, &retval.exponent);
Packit 78deda
Packit 78deda
    return retval;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
rtob (real_t        const f,
Packit 78deda
      const rpf_t * const rpfP)
Packit 78deda
/*
Packit 78deda
 *  Convert real number 'f' into fixed point format.
Packit 78deda
 *  The real number in [-'range'; +'range'] is scaled to [-1 ; +1].
Packit 78deda
 *  Sign and the first 'precision' - 1 bits of the mantissa are
Packit 78deda
 *  packed into one integer.  
Packit 78deda
 *
Packit 78deda
 *  Return value:
Packit 78deda
 *  real value in reduced precision format
Packit 78deda
 */
Packit 78deda
{  
Packit 78deda
    /*
Packit 78deda
     *  Extract mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
Packit 78deda
     */
Packit 78deda
Packit 78deda
    double const normalized = f / rpfP->range;
Packit 78deda
        /* 'f' scaled to [-1,+1] */    
Packit 78deda
    FracExp const fracExp = fracExpFromDouble(normalized);
Packit 78deda
    unsigned int const signedMantissa =
Packit 78deda
        (unsigned int) (fracExp.fraction * (1<<23));
Packit 78deda
Packit 78deda
    unsigned int mantissa;
Packit 78deda
    unsigned int sign;  /* 0 for positive; 1 for negative */
Packit 78deda
    
Packit 78deda
    if (signedMantissa < 0) {
Packit 78deda
        mantissa = -signedMantissa;
Packit 78deda
        sign = 1;
Packit 78deda
    } else {
Packit 78deda
        mantissa = +signedMantissa;
Packit 78deda
        sign = 0;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    /*
Packit 78deda
     *  Generate reduced precision mantissa.
Packit 78deda
     */
Packit 78deda
    if (fracExp.exponent > 0) 
Packit 78deda
        mantissa <<= fracExp.exponent;
Packit 78deda
    else
Packit 78deda
        mantissa >>= -fracExp.exponent;  
Packit 78deda
    
Packit 78deda
    mantissa >>= (23 - rpfP->mantissa_bits - 1);
Packit 78deda
Packit 78deda
    mantissa +=  1;          /* Round last bit. */
Packit 78deda
    mantissa >>= 1;
Packit 78deda
   
Packit 78deda
    if (mantissa == 0)           /* close to zero */
Packit 78deda
        return RPF_ZERO;
Packit 78deda
    else if (mantissa >= (1U << rpfP->mantissa_bits)) /* overflow */
Packit 78deda
        return sign;
Packit 78deda
    else
Packit 78deda
        return ((mantissa & ((1U << rpfP->mantissa_bits) - 1)) << 1) | sign;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
float
Packit 78deda
btor (int           const binary,
Packit 78deda
      const rpf_t * const rpfP)
Packit 78deda
/*
Packit 78deda
 *  Convert value 'binary' in reduced precision format to a real value.
Packit 78deda
 *  For more information refer to function rtob() above.
Packit 78deda
 *
Packit 78deda
 *  Return value:
Packit 78deda
 *  converted value
Packit 78deda
 */
Packit 78deda
{
Packit 78deda
    unsigned int mantissa;
Packit 78deda
    float sign;
Packit 78deda
    float f;
Packit 78deda
 
Packit 78deda
    if (binary == RPF_ZERO)
Packit 78deda
        return 0;
Packit 78deda
Packit 78deda
    if (binary < 0 || binary >= 1 << (rpfP->mantissa_bits + 1))
Packit 78deda
        error ("Reduced precision format: value %d out of range.", binary);
Packit 78deda
Packit 78deda
    /*
Packit 78deda
     *  Restore IEEE float format:
Packit 78deda
     *  mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
Packit 78deda
     */
Packit 78deda
   
Packit 78deda
    sign       = (binary & 0x1) == 0 ? 1.0 : -1.0;
Packit 78deda
    mantissa   = (binary & ((0x1 << (rpfP->mantissa_bits + 1)) - 1)) >> 1; 
Packit 78deda
    mantissa <<= (23 - rpfP->mantissa_bits);
Packit 78deda
Packit 78deda
    if (mantissa == 0) 
Packit 78deda
        f = sign;
Packit 78deda
    else
Packit 78deda
        f =  sign * (float) mantissa / 8388608;
Packit 78deda
   
Packit 78deda
    return f * rpfP->range;       /* expand [ -1 ; +1 ] to
Packit 78deda
                                     [ -range ; +range ] */
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
rpf_t *
Packit 78deda
alloc_rpf (unsigned           const mantissa,
Packit 78deda
           fiasco_rpf_range_e const range)
Packit 78deda
/*
Packit 78deda
 *  Reduced precision format constructor.
Packit 78deda
 *  Allocate memory for the rpf_t structure.
Packit 78deda
 *  Number of mantissa bits is given by `mantissa'.
Packit 78deda
 *  The range of the real values is in the interval [-`range', +`range'].
Packit 78deda
 *  In case of invalid parameters, a structure with default values is
Packit 78deda
 *  returned. 
Packit 78deda
 *
Packit 78deda
 *  Return value
Packit 78deda
 *  pointer to the new rpf structure
Packit 78deda
 */
Packit 78deda
{
Packit 78deda
    rpf_t * rpfP;
Packit 78deda
Packit 78deda
    MALLOCVAR(rpfP);
Packit 78deda
   
Packit 78deda
    if (mantissa < 2) {
Packit 78deda
        warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
Packit 78deda
                   "Using minimum value 2.\n"));
Packit 78deda
        rpfP->mantissa_bits = 2;
Packit 78deda
    } else if (mantissa > 8) {
Packit 78deda
        warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
Packit 78deda
                   "Using maximum value 8.\n"));
Packit 78deda
        rpfP->mantissa_bits = 2;
Packit 78deda
    } else
Packit 78deda
        rpfP->mantissa_bits = mantissa;
Packit 78deda
Packit 78deda
    switch (range) {
Packit 78deda
    case FIASCO_RPF_RANGE_0_75:
Packit 78deda
        rpfP->range   = 0.75;
Packit 78deda
        rpfP->range_e = range;
Packit 78deda
        break;
Packit 78deda
    case FIASCO_RPF_RANGE_1_50:
Packit 78deda
        rpfP->range   = 1.50;
Packit 78deda
        rpfP->range_e = range;
Packit 78deda
        break;
Packit 78deda
    case FIASCO_RPF_RANGE_2_00:
Packit 78deda
        rpfP->range   = 2.00;
Packit 78deda
        rpfP->range_e = range;
Packit 78deda
        break;
Packit 78deda
    case FIASCO_RPF_RANGE_1_00:
Packit 78deda
        rpfP->range   = 1.00;
Packit 78deda
        rpfP->range_e = range;
Packit 78deda
        break;
Packit 78deda
    default:
Packit 78deda
        warning (_("Invalid RPF range specified. Using default value 1.0."));
Packit 78deda
        rpfP->range   = 1.00;
Packit 78deda
        rpfP->range_e = FIASCO_RPF_RANGE_1_00;
Packit 78deda
        break;
Packit 78deda
    }
Packit 78deda
    return rpfP;
Packit 78deda
}
Packit 78deda