decode_big.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 330 行
C
330 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ */#include <string.h>#include <stdlib.h>#include "eidef.h"#include "eiext.h"#include "putget.h"int ei_decode_big(const char *buf, int *index, erlang_big *b){ long digit_bytes; const char *s = buf + *index; const char *s0 = s; switch ( get8(s) ) { case ERL_SMALL_BIG_EXT: digit_bytes = get8(s); break; case ERL_LARGE_BIG_EXT: digit_bytes = get32be(s); break; default: return -1; } if ( b ) { unsigned short *dt = b->digits; int i; unsigned char *u; if ( ((digit_bytes+1)/2) != b->arity ) { return -1; } b->is_neg = get8(s); u = (unsigned char *) s; for (i = 0; i < b->arity; ++i) { dt[i] = u[i*2]; dt[i] |= ((unsigned short) u[(i*2)+1]) << 8; } } else { s++; /* skip sign byte */ } s += digit_bytes; *index += s-s0; return 0; }erlang_big *ei_alloc_big(int arity){ erlang_big *b; if ( (b = malloc(sizeof(erlang_big))) == NULL) return NULL; memset(b,(char)0,sizeof(erlang_big)); if ( (b->digits = malloc(arity*2)) == NULL) { free(b); return 0; } b->arity = arity; memset(b->digits,(char)0,arity*2); return b;}void ei_free_big(erlang_big *b){ if (!b) return; if (b->digits) free(b->digits); free(b);}/* big compare functions */typedef unsigned short Uint16;typedef unsigned int Uint;typedef Uint16 digit_t;typedef Uint dsize_t;static int I_comp(digit_t *x, dsize_t xl, digit_t *y, dsize_t yl){ if (xl<yl) { return -1; } else if (xl>yl) { return 1; } else { if ( x == y ) return 0; x += (xl-1); y += (yl-1); while( (xl>0) && (*x==*y) ) { x--; y--; xl--; } if ( xl == 0 ) return 0; return ( *x < *y ) ? -1 : 1; }}int ei_big_comp(erlang_big *x, erlang_big *y){ if ( x->is_neg == y->is_neg ) { int c = I_comp(x->digits,x->arity,y->digits,y->arity); if ( x->is_neg ) return -c; else return c; } else { return x->is_neg ? -1 : 1; }}#define D_EXP 16#define D_BASE (1<<D_EXP)#define D_DECIMAL_EXP 4 /* 10^4 == 10000 */#define D_DECIMAL_BASE 10000 /* Max decimal exponent in a digit */#define DLOW(x) ((digit_t)((x) & (D_BASE-1)))#define DHIGH(x) ((digit_t)((x) >> D_EXP))/* * Handling of floating point exceptions. */#if defined(VXWORKS) && CPU == PPC860#undef NO_FPE_SIGNALS#define NO_FPE_SIGNALS 1#undef INLINED_FP_CONVERSION#define INLINED_FP_CONVERSION 1#endif#ifdef USE_ISINF_ISNAN /* simulate finite() */# define finite(f) (!isinf(f) && !isnan(f))# define HAVE_FINITE#endif#ifdef NO_FPE_SIGNALS# define ERTS_FP_CHECK_INIT() do {} while (0)# define ERTS_FP_ERROR(f, Action) if (!finite(f)) { Action; } else {}# define ERTS_SAVE_FP_EXCEPTION()# define ERTS_RESTORE_FP_EXCEPTION()#else/* extern volatile int erl_fp_exception; */static volatile int erl_fp_exception;# define ERTS_FP_CHECK_INIT() do {erl_fp_exception = 0;} while (0)# if defined(__i386__) && defined(__GNUC__)/* extern void erts_restore_x87(void); */static void unmask_fpe(void){ unsigned short cw; __asm__ __volatile__("fstcw %0" : "=m"(cw)); cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */ __asm__ __volatile__("fldcw %0" : : "m"(cw));}static void erts_restore_x87(void){ __asm__ __volatile__("fninit"); unmask_fpe();}static int erts_check_x87(double f){ __asm__ __volatile__("fwait" : "=m"(erl_fp_exception) : "m"(f)); if( !erl_fp_exception ) return 0; erts_restore_x87(); return 1;}# define ERTS_FP_ERROR(f, Action) do { if( erts_check_x87((f)) ) { Action; } } while (0)# else# define ERTS_FP_ERROR(f, Action) if (erl_fp_exception) { Action; } else {}# endif# define ERTS_SAVE_FP_EXCEPTION() int old_erl_fp_exception = erl_fp_exception# define ERTS_RESTORE_FP_EXCEPTION() \ do {erl_fp_exception = old_erl_fp_exception;} while (0)#endif#ifdef INLINED_FP_CONVERSIONstatic void join(unsigned d_split[4], unsigned *d){ d[0] = (d_split[0] << 31) | /* Sign bit */ ((d_split[1] & 0x7FFU) << 20) | /* Exponent */ (d_split[2] & 0xFFFFFU); /* Mantissa MS bits */ d[1] = d_split[3]; /* Mantissa LS bits */}static int blength(unsigned long l){ int i; for(i = 0; l; ++i) l >>= 1; return i;}static int bblength(erlang_big *b){ unsigned wholebytes = b->arity; digit_t *dp = b->digits; while(wholebytes > 0 && dp[--wholebytes] == 0U) ; return (wholebytes * sizeof(digit_t) * 8) + blength(dp[wholebytes]);}static unsigned long bindex(erlang_big *b, int ndx) { digit_t *dp = b->digits; int skipdigits; int dnum; if (ndx < 0) return 0; skipdigits = ndx / (sizeof(digit_t) * 8); dnum = ndx % (sizeof(digit_t) * 8); return !!(dp[skipdigits] & (1UL << dnum));}#endifint ei_big_to_double(erlang_big *b, double *resp){#ifdef INLINED_FP_CONVERSION unsigned d_split[4]; unsigned *uresp = (unsigned *) resp; unsigned len = bblength(b); int i; unsigned long msm = 0, lsm = 0; /* OK, this is not the most efficient conversion in the world, especially not the bit-by-bit copying to the mantissa.... Simple, working and only for vxworks ppc860 where no sane person would use floating point anyway, eh? /Patrik */ if (!len) { memset(d_split,0,sizeof(d_split)); /* 0 */ } else { --len; if (len > 1023) { /* Infinite */ d_split[1] = 2047; d_split[2] = d_split[3] = 0; } else { d_split[1] = 1023 + len; --len; /* skip the implicit binary 1. */ for (i = 0; i < 20; ++i, --len) { msm <<= 1; msm |= bindex(b,len); } for (i = 0; i < 32; ++i, --len) { lsm <<= 1; lsm |= bindex(b,len); } d_split[2] = msm; d_split[3] = lsm; } } d_split[0] = (unsigned) !!(b->is_neg); join(d_split,uresp); return 0;#else double d = 0.0; double d_base = 1.0; digit_t* s = (digit_t *)b->digits; dsize_t xl = b->arity; short xsgn = b->is_neg; ERTS_SAVE_FP_EXCEPTION(); ERTS_FP_CHECK_INIT(); while(xl--) { digit_t ds = *s; double d_next = ds * d_base + d; ERTS_FP_ERROR(d_next, ERTS_RESTORE_FP_EXCEPTION(); {fprintf(stderr,"\r\n### fp exception ###\r\n"); return -1;}); s++; d = d_next; d_base *= D_BASE; } /* * Note: The last multiplication in the loop could trigger an exception, * which we will ignore because the result will never be used. */ *resp = xsgn ? -d : d; ERTS_FP_ERROR(*resp,;); ERTS_RESTORE_FP_EXCEPTION(); return 0;#endif}int ei_small_to_big(int s, erlang_big *b){ digit_t *d; if ( b->arity < 2 ) return -1; b->is_neg = ( s < 0 ); d = (digit_t *)b->digits; d[0] = DLOW(s); d[1] = DHIGH(s); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?