Home | History | Annotate | Line # | Download | only in libparse
ieee754io.c revision 1.5
      1 /*	$NetBSD: ieee754io.c,v 1.5 2020/05/25 20:47:25 christos Exp $	*/
      2 
      3 /*
      4  * /src/NTP/ntp4-dev/libntp/ieee754io.c,v 4.12 2005/04/16 17:32:10 kardel RELEASE_20050508_A
      5  *
      6  * ieee754io.c,v 4.12 2005/04/16 17:32:10 kardel RELEASE_20050508_A
      7  *
      8  * $Created: Sun Jul 13 09:12:02 1997 $
      9  *
     10  * Copyright (c) 1997-2005 by Frank Kardel <kardel <AT> ntp.org>
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the author nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  */
     37 
     38 #ifdef HAVE_CONFIG_H
     39 #include "config.h"
     40 #endif
     41 
     42 #include <stdio.h>
     43 #include "l_stdlib.h"
     44 #include "ntp_stdlib.h"
     45 #include "ntp_fp.h"
     46 #include "ieee754io.h"
     47 
     48 static unsigned char get_byte (unsigned char *, offsets_t, int *);
     49 #ifdef __not_yet__
     50 static void put_byte (unsigned char *, offsets_t, int *, unsigned char);
     51 #endif
     52 
     53 #ifdef LIBDEBUG
     54 
     55 #include "lib_strbuf.h"
     56 
     57 static char *
     58 fmt_blong(
     59 	  unsigned long val,
     60 	  int cnt
     61 	  )
     62 {
     63   char *buf, *s;
     64   int i = cnt;
     65 
     66   val <<= 32 - cnt;
     67   LIB_GETBUF(buf);
     68   s = buf;
     69 
     70   while (i--)
     71     {
     72       if (val & 0x80000000)
     73 	{
     74 	  *s++ = '1';
     75 	}
     76       else
     77 	{
     78 	  *s++ = '0';
     79 	}
     80       val <<= 1;
     81     }
     82   *s = '\0';
     83   return buf;
     84 }
     85 
     86 static char *
     87 fmt_flt(
     88 	unsigned int sign,
     89 	unsigned long mh,
     90 	unsigned long ml,
     91 	unsigned long ch
     92 	)
     93 {
     94 	char *buf;
     95 
     96 	LIB_GETBUF(buf);
     97 	snprintf(buf, LIB_BUFLENGTH, "%c %s %s %s", sign ? '-' : '+',
     98 		 fmt_blong(ch, 11),
     99 		 fmt_blong(mh, 20),
    100 		 fmt_blong(ml, 32));
    101 
    102 	return buf;
    103 }
    104 
    105 static char *
    106 fmt_hex(
    107 	unsigned char *bufp,
    108 	int length
    109 	)
    110 {
    111 	char *	buf;
    112 	char	hex[4];
    113 	int	i;
    114 
    115 	LIB_GETBUF(buf);
    116 	buf[0] = '\0';
    117 	for (i = 0; i < length; i++) {
    118 		snprintf(hex, sizeof(hex), "%02x", bufp[i]);
    119 		strlcat(buf, hex, LIB_BUFLENGTH);
    120 	}
    121 
    122 	return buf;
    123 }
    124 
    125 #endif
    126 
    127 static unsigned char
    128 get_byte(
    129 	 unsigned char *bufp,
    130 	 offsets_t offset,
    131 	 int *fieldindex
    132 	 )
    133 {
    134   unsigned char val;
    135 
    136   val     = *(bufp + offset[*fieldindex]);
    137 #ifdef LIBDEBUG
    138   if (debug > 4)
    139     printf("fetchieee754: getbyte(0x%08x, %d) = 0x%02x\n", (unsigned int)(bufp)+offset[*fieldindex], *fieldindex, val);
    140 #endif
    141   (*fieldindex)++;
    142   return val;
    143 }
    144 
    145 #ifdef __not_yet__
    146 static void
    147 put_byte(
    148 	 unsigned char *bufp,
    149 	 offsets_t offsets,
    150 	 int *fieldindex,
    151 	 unsigned char val
    152 	 )
    153 {
    154   *(bufp + offsets[*fieldindex]) = val;
    155   (*fieldindex)++;
    156 }
    157 #endif
    158 
    159 /*
    160  * make conversions to and from external IEEE754 formats and internal
    161  * NTP FP format.
    162  */
    163 int
    164 fetch_ieee754(
    165 	      unsigned char **buffpp,
    166 	      int size,
    167 	      l_fp *lfpp,
    168 	      offsets_t offsets
    169 	      )
    170 {
    171   unsigned char *bufp = *buffpp;
    172   unsigned int sign;
    173   unsigned int bias;
    174   unsigned int maxexp;
    175   int mbits;
    176   u_long mantissa_low;
    177   u_long mantissa_high;
    178   u_long characteristic;
    179   long exponent;
    180 #ifdef LIBDEBUG
    181   int length;
    182 #endif
    183   unsigned char val;
    184   int fieldindex = 0;
    185 
    186   switch (size)
    187     {
    188     case IEEE_DOUBLE:
    189 #ifdef LIBDEBUG
    190       length = 8;
    191 #endif
    192       mbits  = 52;
    193       bias   = 1023;
    194       maxexp = 2047;
    195       break;
    196 
    197     case IEEE_SINGLE:
    198 #ifdef LIBDEBUG
    199       length = 4;
    200 #endif
    201       mbits  = 23;
    202       bias   = 127;
    203       maxexp = 255;
    204       break;
    205 
    206     default:
    207       return IEEE_BADCALL;
    208     }
    209 
    210   val = get_byte(bufp, offsets, &fieldindex); /* fetch sign byte & first part of characteristic */
    211 
    212   sign     = (val & 0x80) != 0;
    213   characteristic = (val & 0x7F);
    214 
    215   val = get_byte(bufp, offsets, &fieldindex); /* fetch rest of characteristic and start of mantissa */
    216 
    217   switch (size)
    218     {
    219     case IEEE_SINGLE:
    220       characteristic <<= 1;
    221       characteristic  |= (val & 0x80) != 0; /* grab last characteristic bit */
    222 
    223       mantissa_high  = 0;
    224 
    225       mantissa_low   = (val &0x7F) << 16;
    226       mantissa_low  |= (u_long)get_byte(bufp, offsets, &fieldindex) << 8;
    227       mantissa_low  |= get_byte(bufp, offsets, &fieldindex);
    228       break;
    229 
    230     case IEEE_DOUBLE:
    231       characteristic <<= 4;
    232       characteristic  |= (val & 0xF0) >> 4; /* grab lower characteristic bits */
    233 
    234       mantissa_high  = (val & 0x0F) << 16;
    235       mantissa_high |= (u_long)get_byte(bufp, offsets, &fieldindex) << 8;
    236       mantissa_high |= get_byte(bufp, offsets, &fieldindex);
    237 
    238       mantissa_low   = (u_long)get_byte(bufp, offsets, &fieldindex) << 24;
    239       mantissa_low  |= (u_long)get_byte(bufp, offsets, &fieldindex) << 16;
    240       mantissa_low  |= (u_long)get_byte(bufp, offsets, &fieldindex) << 8;
    241       mantissa_low  |= get_byte(bufp, offsets, &fieldindex);
    242       break;
    243 
    244     default:
    245       return IEEE_BADCALL;
    246     }
    247 #ifdef LIBDEBUG
    248   if (debug > 4)
    249   {
    250     double d;
    251     float f;
    252 
    253     if (size == IEEE_SINGLE)
    254       {
    255 	int i;
    256 
    257 	for (i = 0; i < length; i++)
    258 	  {
    259 	    *((unsigned char *)(&f)+i) = *(*buffpp + offsets[i]);
    260 	  }
    261 	d = f;
    262       }
    263     else
    264       {
    265 	int i;
    266 
    267 	for (i = 0; i < length; i++)
    268 	  {
    269 	    *((unsigned char *)(&d)+i) = *(*buffpp + offsets[i]);
    270 	  }
    271       }
    272 
    273     printf("fetchieee754: FP: %s -> %s -> %e(=%s)\n", fmt_hex(*buffpp, length),
    274 	   fmt_flt(sign, mantissa_high, mantissa_low, characteristic),
    275 	   d, fmt_hex((unsigned char *)&d, length));
    276   }
    277 #endif
    278 
    279   *buffpp += fieldindex;
    280 
    281   /*
    282    * detect funny numbers
    283    */
    284   if (characteristic == maxexp)
    285     {
    286       /*
    287        * NaN or Infinity
    288        */
    289       if (mantissa_low || mantissa_high)
    290 	{
    291 	  /*
    292 	   * NaN
    293 	   */
    294 	  return IEEE_NAN;
    295 	}
    296       else
    297 	{
    298 	  /*
    299 	   * +Inf or -Inf
    300 	   */
    301 	  return sign ? IEEE_NEGINFINITY : IEEE_POSINFINITY;
    302 	}
    303     }
    304   else
    305     {
    306       /*
    307        * collect real numbers
    308        */
    309 
    310       L_CLR(lfpp);
    311 
    312       /*
    313        * check for overflows
    314        */
    315       exponent = characteristic - bias;
    316 
    317       if (exponent > 31)	/* sorry - hardcoded */
    318 	{
    319 	  /*
    320 	   * overflow only in respect to NTP-FP representation
    321 	   */
    322 	  return sign ? IEEE_NEGOVERFLOW : IEEE_POSOVERFLOW;
    323 	}
    324       else
    325 	{
    326 	  int frac_offset;	/* where the fraction starts */
    327 
    328 	  frac_offset = mbits - exponent;
    329 
    330 	  if (characteristic == 0)
    331 	    {
    332 	      /*
    333 	       * de-normalized or tiny number - fits only as 0
    334 	       */
    335 	      return IEEE_OK;
    336 	    }
    337 	  else
    338 	    {
    339 	      /*
    340 	       * adjust for implied 1
    341 	       */
    342 	      if (mbits > 31)
    343 		mantissa_high |= 1 << (mbits - 32);
    344 	      else
    345 		mantissa_low  |= 1 << mbits;
    346 
    347 	      /*
    348 	       * take mantissa apart - if only all machine would support
    349 	       * 64 bit operations 8-(
    350 	       */
    351 	      if (frac_offset > mbits)
    352 		{
    353 		  lfpp->l_ui = 0; /* only fractional number */
    354 		  frac_offset -= mbits + 1; /* will now contain right shift count - 1*/
    355 		  if (mbits > 31)
    356 		    {
    357 		      lfpp->l_uf   = mantissa_high << (63 - mbits);
    358 		      lfpp->l_uf  |= mantissa_low  >> (mbits - 33);
    359 		      lfpp->l_uf >>= frac_offset;
    360 		    }
    361 		  else
    362 		    {
    363 		      lfpp->l_uf = mantissa_low >> frac_offset;
    364 		    }
    365 		}
    366 	      else
    367 		{
    368 		  if (frac_offset > 32)
    369 		    {
    370 		      /*
    371 		       * must split in high word
    372 		       */
    373 		      lfpp->l_ui  =  mantissa_high >> (frac_offset - 32);
    374 		      lfpp->l_uf  = (mantissa_high & ((1 << (frac_offset - 32)) - 1)) << (64 - frac_offset);
    375 		      lfpp->l_uf |=  mantissa_low  >> (frac_offset - 32);
    376 		    }
    377 		  else
    378 		    {
    379 		      /*
    380 		       * must split in low word
    381 		       */
    382 		      lfpp->l_ui  =  mantissa_high << (32 - frac_offset);
    383 		      lfpp->l_ui |= (mantissa_low >> frac_offset) & ((1 << (32 - frac_offset)) - 1);
    384 		      lfpp->l_uf  = (mantissa_low & ((1 << frac_offset) - 1)) << (32 - frac_offset);
    385 		    }
    386 		}
    387 
    388 	      /*
    389 	       * adjust for sign
    390 	       */
    391 	      if (sign)
    392 		{
    393 		  L_NEG(lfpp);
    394 		}
    395 
    396 	      return IEEE_OK;
    397 	    }
    398 	}
    399     }
    400 }
    401 
    402 int
    403 put_ieee754(
    404 	    unsigned char **bufpp,
    405 	    int size,
    406 	    l_fp *lfpp,
    407 	    offsets_t offsets
    408 	    )
    409 {
    410   l_fp outlfp;
    411 #ifdef LIBDEBUG
    412   unsigned int sign;
    413   unsigned int bias;
    414 #endif
    415 /*unsigned int maxexp;*/
    416   int mbits;
    417   int msb;
    418   u_long mantissa_low = 0;
    419   u_long mantissa_high = 0;
    420 #ifdef LIBDEBUG
    421   u_long characteristic = 0;
    422   long exponent;
    423 #endif
    424 /*int length;*/
    425   unsigned long mask;
    426 
    427   outlfp = *lfpp;
    428 
    429   switch (size)
    430     {
    431     case IEEE_DOUBLE:
    432     /*length = 8;*/
    433       mbits  = 52;
    434 #ifdef LIBDEBUG
    435       bias   = 1023;
    436 #endif
    437     /*maxexp = 2047;*/
    438       break;
    439 
    440     case IEEE_SINGLE:
    441     /*length = 4;*/
    442       mbits  = 23;
    443 #ifdef LIBDEBUG
    444       bias   = 127;
    445 #endif
    446     /*maxexp = 255;*/
    447       break;
    448 
    449     default:
    450       return IEEE_BADCALL;
    451     }
    452 
    453   /*
    454    * find sign
    455    */
    456   if (L_ISNEG(&outlfp))
    457     {
    458       L_NEG(&outlfp);
    459 #ifdef LIBDEBUG
    460       sign = 1;
    461 #endif
    462     }
    463   else
    464     {
    465 #ifdef LIBDEBUG
    466       sign = 0;
    467 #endif
    468     }
    469 
    470   if (L_ISZERO(&outlfp))
    471     {
    472 #ifdef LIBDEBUG
    473       exponent = mantissa_high = mantissa_low = 0; /* true zero */
    474 #endif
    475     }
    476   else
    477     {
    478       /*
    479        * find number of significant integer bits
    480        */
    481       mask = 0x80000000;
    482       if (outlfp.l_ui)
    483 	{
    484 	  msb = 63;
    485 	  while (mask && ((outlfp.l_ui & mask) == 0))
    486 	    {
    487 	      mask >>= 1;
    488 	      msb--;
    489 	    }
    490 	}
    491       else
    492 	{
    493 	  msb = 31;
    494 	  while (mask && ((outlfp.l_uf & mask) == 0))
    495 	    {
    496 	      mask >>= 1;
    497 	      msb--;
    498 	    }
    499 	}
    500 
    501       switch (size)
    502 	{
    503 	case IEEE_SINGLE:
    504 	  mantissa_high = 0;
    505 	  if (msb >= 32)
    506 	    {
    507 	      mantissa_low  = (outlfp.l_ui & ((1 << (msb - 32)) - 1)) << (mbits - (msb - 32));
    508 	      mantissa_low |=  outlfp.l_uf >> (mbits - (msb - 32));
    509 	    }
    510 	  else
    511 	    {
    512 	      mantissa_low  = (outlfp.l_uf << (mbits - msb)) & ((1 << mbits) - 1);
    513 	    }
    514 	  break;
    515 
    516 	case IEEE_DOUBLE:
    517 	  if (msb >= 32)
    518 	    {
    519 	      mantissa_high  = (outlfp.l_ui << (mbits - msb)) & ((1 << (mbits - 32)) - 1);
    520 	      mantissa_high |=  outlfp.l_uf >> (32 - (mbits - msb));
    521 	      mantissa_low   = (outlfp.l_ui & ((1 << (msb - mbits)) - 1)) << (32 - (msb - mbits));
    522 	      mantissa_low  |=  outlfp.l_uf >> (msb - mbits);
    523 	    }
    524 	  else
    525 	    {
    526 	      mantissa_high  = outlfp.l_uf << (mbits - 32 - msb);
    527 	      mantissa_low   = outlfp.l_uf << (mbits - 32);
    528 	    }
    529 	}
    530 
    531 #ifdef LIBDEBUG
    532       exponent = msb - 32;
    533       characteristic = exponent + bias;
    534 
    535       if (debug > 4)
    536 	printf("FP: %s\n", fmt_flt(sign, mantissa_high, mantissa_low, characteristic));
    537 #endif
    538     }
    539   return IEEE_OK;
    540 }
    541 
    542 
    543 #if defined(DEBUG) && defined(LIBDEBUG)
    544 int main(
    545 	 int argc,
    546 	 char **argv
    547 	 )
    548 {
    549   static offsets_t native_off = { 0, 1, 2, 3, 4, 5, 6, 7 };
    550   double f = 1.0;
    551   double *f_p = &f;
    552   l_fp fp;
    553 
    554   if (argc == 2)
    555     {
    556       if (sscanf(argv[1], "%lf", &f) != 1)
    557 	{
    558 	  printf("cannot convert %s to a float\n", argv[1]);
    559 	  return 1;
    560 	}
    561     }
    562 
    563   printf("double: %s %s\n", fmt_blong(*(unsigned long *)&f, 32), fmt_blong(*(unsigned long *)((char *)(&f)+4), 32));
    564   printf("fetch from %f = %d\n", f, fetch_ieee754((void *)&f_p, IEEE_DOUBLE, &fp, native_off));
    565   printf("fp [%s %s] = %s\n", fmt_blong(fp.l_ui, 32), fmt_blong(fp.l_uf, 32), mfptoa(fp.l_ui, fp.l_uf, 15));
    566   f_p = &f;
    567   put_ieee754((void *)&f_p, IEEE_DOUBLE, &fp, native_off);
    568 
    569   return 0;
    570 }
    571 
    572 #endif
    573 /*
    574  * History:
    575  *
    576  * ieee754io.c,v
    577  * Revision 4.12  2005/04/16 17:32:10  kardel
    578  * update copyright
    579  *
    580  * Revision 4.11  2004/11/14 15:29:41  kardel
    581  * support PPSAPI, upgrade Copyright to Berkeley style
    582  *
    583  * Revision 4.8  1999/02/21 12:17:36  kardel
    584  * 4.91f reconcilation
    585  *
    586  * Revision 4.7  1999/02/21 11:26:03  kardel
    587  * renamed index to fieldindex to avoid index() name clash
    588  *
    589  * Revision 4.6  1998/11/15 20:27:52  kardel
    590  * Release 4.0.73e13 reconcilation
    591  *
    592  * Revision 4.5  1998/08/16 19:01:51  kardel
    593  * debug information only compile for LIBDEBUG case
    594  *
    595  * Revision 4.4  1998/08/09 09:39:28  kardel
    596  * Release 4.0.73e2 reconcilation
    597  *
    598  * Revision 4.3  1998/06/13 11:56:19  kardel
    599  * disabled putbute() for the time being
    600  *
    601  * Revision 4.2  1998/06/12 15:16:58  kardel
    602  * ansi2knr compatibility
    603  *
    604  * Revision 4.1  1998/05/24 07:59:56  kardel
    605  * conditional debug support
    606  *
    607  * Revision 4.0  1998/04/10 19:46:29  kardel
    608  * Start 4.0 release version numbering
    609  *
    610  * Revision 1.1  1998/04/10 19:27:46  kardel
    611  * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
    612  *
    613  * Revision 1.1  1997/10/06 21:05:45  kardel
    614  * new parse structure
    615  *
    616  */
    617