/* "bytenumb.scm" Byte integer and IEEE floating-point conversions.
* Copyright (C) 2007 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* .
*/
/* Author: Aubrey Jaffer */
/* For documentation see:
http://cvs.savannah.gnu.org/viewcvs/slib/slib/bytenumb.scm?view=markup */
#include
#include
#include "scm.h"
int get_bytes_length(obj)
SCM obj;
{
array_dim *s;
if (IMP(obj)) return -1;
switch (TYP7(obj)) {
case tc7_string:
case tc7_VfixN8:
case tc7_VfixZ8:
return LENGTH(obj);
case tc7_smob:
if (!ARRAYP(obj)) return -1;
if (1 != ARRAY_NDIM(obj)) return -1;
s = ARRAY_DIMS(obj);
if (1 != s[0].inc) return -1;
return s[0].ubnd - s[0].lbnd;
default: return -1;
}
}
static char s_wrong_length[] = "wrong length";
static SCM list_of_0;
char * get_bytes(obj, minlen, s_name)
SCM obj;
int minlen;
const char *s_name;
{
ASRTER(NIMP(obj) && (TYP7(obj)==tc7_string ||
TYP7(obj)==tc7_VfixN8 ||
TYP7(obj)==tc7_VfixZ8),
obj, ARG1, s_name);
{
int byvlen = get_bytes_length(obj);
ASRTER(byvlen >= minlen, obj, s_wrong_length, s_name);
return (char*)scm_addr(cons(obj, list_of_0), s_name);
}
}
static char s_bytes_to_integer[] = "bytes->integer";
SCM scm_bytes_to_integer(sbyts, sn)
SCM sbyts;
SCM sn;
{
long n = INUM(sn);
if (!(n)) return INUM0;
{
int cnt = abs(n);
char *byts = get_bytes(sbyts, cnt, s_bytes_to_integer);
int iu = 0, id = cnt - sizeof(BIGDIG);
sizet ndigs = (cnt + sizeof(BIGDIG) - 1) / sizeof(BIGDIG);
int negp = (0x80 & byts[0]) && (0 > n);
SCM retval = mkbig(ndigs, negp);
BIGDIG *digs = BDIGITS(retval), carry = 1;
if (negp)
for (; iu < ndigs; iu++) {
int j = 0;
unsigned long dig = 0;
for (; j < sizeof(BIGDIG); j++) {
dig = (dig<<8) +
(0xFF ^ ((id + j >= 0) ? (((unsigned char *)byts)[id + j]) : 255));
/* printf("byts[%d + %d] = %lx\n", id, j, 0xFF & dig); */
}
dig = dig + carry;
digs[iu] = dig;
carry = dig >> (8 * sizeof(BIGDIG));
/* printf("id = %d; iu = %d; dig = %04lx\n", id, iu, dig); */
id = id - sizeof(BIGDIG);
} else
for (; iu < ndigs; iu++) {
int j = 0;
BIGDIG dig = 0;
for (; j < sizeof(BIGDIG); j++) {
dig = (dig<<8) +
((id + j >= 0) ? (((unsigned char *)byts)[id + j]) : 0);
}
digs[iu] = dig;
/* printf("id = %d; iu = %d; dig = %04x\n", id, iu, dig); */
id = id - sizeof(BIGDIG);
}
return normbig(retval);
}
}
static char s_integer_to_bytes[] = "integer->bytes";
SCM scm_integer_to_bytes(sn, slen)
SCM sn;
SCM slen;
{
ASRTER(INUMP(slen), slen, ARG2, s_integer_to_bytes);
{
int len = INUM(slen);
SCM sbyts = make_string(scm_iabs(slen), MAKICHR(0));
char *byts = CHARS(sbyts);
if (INUMP(sn)) {
int idx = -1 + (abs(len));
long n = num2long(sn, (char *)ARG1, s_integer_to_bytes);
if ((0 > n) && (0 > len)) {
long res = -1 - n;
while (!(0 > idx)) {
byts[idx--] = 0xFF ^ (res % 0x100);
res = res>>8;
}
}
else {
unsigned long res = n;
while (!(0 > idx)) {
byts[idx--] = res % 0x100;
res = res>>8;
}
}
} else {
ASRTER(NIMP(sn) && BIGP(sn), sn, ARG1, s_integer_to_bytes);
{
BIGDIG *digs = BDIGITS(sn), borrow = 1;
sizet ndigs = NUMDIGS(sn);
int iu = 0, id = abs(len) - 1;
unsigned long dig;
if ((0 > len) && (TYP16(sn)==tc16_bigneg))
for (; 0 <= id ; iu++) {
sizet j = sizeof(BIGDIG);
dig = (iu < ndigs) ? digs[iu] : 0;
dig = dig ^ ((1 << (8 * sizeof(BIGDIG))) - 1);
/* printf("j = %d; id = %d; iu = %d; dig = %04x; borrow = %d\n", j, id, iu, dig, borrow); */
for (; 0 < j-- && 0 <= id;) {
/* printf("byts[%d] = %02x\n", id, 0xFF & dig); */
int dg = (0xFF & dig) + borrow;
borrow = dg >> 8;
((unsigned char *)byts)[id--] = dg;
dig = (dig)>>8;
}
}
else
for (; 0 <= id ; iu++) {
BIGDIG dig = (iu < ndigs) ? digs[iu] : 0;
sizet j = sizeof(BIGDIG);
/* printf("j = %d; id = %d; iu = %d; dig = %04x\n", j, id, iu, dig); */
for (; 0 < j-- && 0 <= id;) {
/* printf("byts[%d] = %02x\n", id, 0xFF & dig); */
((unsigned char *)byts)[id--] = 0xFF & dig;
dig = (dig>>8);
}
}
}
}
return sbyts;
}
}
static char s_bytes_to_ieee_float[] = "bytes->ieee-float";
SCM scm_bytes_to_ieee_float(sbyts)
SCM sbyts;
{
char *byts = get_bytes(sbyts, 4, s_bytes_to_ieee_float);
int len = LENGTH(sbyts);
int s = (1<<(7)) & ((((unsigned char*)(byts))[0]));
int e = ((0x7f&((((unsigned char*)(byts))[0])))<<1)
+ ((0x80&((((unsigned char*)(byts))[1])))>>7);
float f = (((unsigned char*)(byts))[ -1 + (len)]);
int idx = -2 + (len);
while (!((idx)<=1)) {
{
int T_idx = -1 + (idx);
f = ((((unsigned char*)(byts))[idx])) + ((f) / 0x100);
idx = T_idx;
}
}
f = ((0x7f&((((unsigned char*)(byts))[1]))) + ((f) / 0x100)) / 0x80;
if ((0<(e))
&& ((e)<0xff))
return makdbl(ldexpf((s ? -1 : 1) * (1 + (f)), (e) - 0x7f), 0.0);
else if (!(e))
if (!(f)) return flo0;
else return makdbl(ldexpf((s ? -1 : 1) * (f), -126), 0.0);
else if (f)
return scm_narn;
else return makdbl((s ? -(1.0) : 1.0) / 0.0, 0.0);
}
static char s_bytes_to_ieee_double[] = "bytes->ieee-double";
SCM scm_bytes_to_ieee_double(sbyts)
SCM sbyts;
{
char *byts = get_bytes(sbyts, 8, s_bytes_to_ieee_double);
int len = LENGTH(sbyts);
int s = (1<<(7)) & ((((unsigned char*)(byts))[0]));
int e = ((0x7f&((((unsigned char*)(byts))[0])))<<4)
+ ((0xf0&((((unsigned char*)(byts))[1])))>>4);
double f = (((unsigned char*)(byts))[ -1 + (len)]);
int idx = -2 + (len);
while (!((idx)<=1)) {
{
int T_idx = -1 + (idx);
f = ((((unsigned char*)(byts))[idx])) + ((f) / 0x100);
idx = T_idx;
}
}
f = ((0xf&((((unsigned char*)(byts))[1]))) + ((f) / 0x100)) / 0x10;
if ((0<(e))
&& ((e)<0x7ff))
return makdbl(ldexp((s ? -1 : 1) * (1 + (f)), (e) - 0x3ff), 0.0);
else if (!(e))
if (!(f)) return flo0;
else return makdbl(ldexp((s ? -1 : 1) * (f), -1022), 0.0);
else if (f)
return scm_narn;
else return makdbl((s ? -(1.0) : 1.0) / 0.0, 0.0);
}
static char s_ieee_float_to_bytes[] = "ieee-float->bytes";
SCM scm_ieee_float_to_bytes(in_flt)
SCM in_flt;
{
double dbl = num2dbl(in_flt, (char *)ARG1, s_ieee_float_to_bytes);
float flt = (float) dbl;
SCM sbyts = make_string(MAKINUM(4), MAKICHR(0));
char *byts = CHARS(sbyts);
int s = flt < 0.0;
int scl = 0x7f;
flt = fabs(flt);
if (0.0==flt) {
if (s)
byts[0] = 0x80;
return sbyts;
}
else if (flt != flt) {
byts[0] = 0x7f;
byts[1] = 0xc0;
return sbyts;
}
else goto L_scale;
L_out:
{
float T_flt = 0x80 * (flt);
int val = (int)(floor(0x80 * (flt)));
int idx = 1;
float flt = T_flt;
while (!((idx) > 3)) {
byts[idx] = val;
{
float T_flt = 0x100 * ((flt) - (val));
int T_val = (int)(floor(0x100 * ((flt) - (val))));
idx = 1 + (idx);
flt = T_flt;
val = T_val;
}
}
byts[1] = (0x80 & (scl<<7)) | (0x7f & (((unsigned char*)(byts))[1]));
byts[0] = (s ? 0x80 : 0) + ((scl)>>1);
return sbyts;
}
L_scale:
if (!(scl)) {
flt = (flt)/2;
goto L_out;
}
else if ((flt)>=0x10) {
float flt16 = (flt) / 0x10;
if ((flt16)==(flt)) {
byts[0] = s ? 0xff : 0x7f;
byts[1] = 0x80;
return sbyts;
}
else {
flt = flt16;
scl = (scl) + 4;
goto L_scale;
}
}
else if ((flt) >= 2) {
flt = (flt) / 2;
scl = (scl) + 1;
goto L_scale;
}
else if (((scl) >= 4) && ((0x10 * (flt))<1)) {
flt = (flt) * 0x10;
scl = (scl)+ -4;
goto L_scale;
}
else if ((flt)<1) {
flt = (flt) * 2;
scl = (scl) + -1;
goto L_scale;
}
else {
flt = -1+(flt);
goto L_out;
}
}
static char s_ieee_double_to_bytes[] = "ieee-double->bytes";
SCM scm_ieee_double_to_bytes(in_flt)
SCM in_flt;
{
double flt = num2dbl(in_flt, (char *)ARG1, s_ieee_double_to_bytes);
SCM sbyts = make_string(MAKINUM(8), MAKICHR(0));
char *byts = CHARS(sbyts);
int s = flt < 0.0;
int scl = 0x3ff;
flt = fabs(flt);
if (0.0==flt) {
if (s)
byts[0] = 0x80;
return sbyts;
}
else if (flt != flt) {
byts[0] = 0x7f;
byts[1] = 0xf8;
return sbyts;
}
else goto L_scale;
L_out:
{
double T_flt = 0x10 * (flt);
int val = (int)(floor(0x10 * (flt)));
int idx = 1;
double flt = T_flt;
while (!((idx) > 7)) {
byts[idx] = val;
{
double T_flt = 0x100 * (flt - val);
int T_val = (int)floor(0x100 * (flt - val));
idx = 1 + (idx);
flt = T_flt;
val = T_val;
}
}
byts[1] = (0xf0 & (scl<<4)) | (0x0f & (((unsigned char*)(byts))[1]));
byts[0] = (s ? 0x80 : 0) + ((scl)>>4);
return sbyts;
}
L_scale:
if (!(scl)) {
flt = (flt) / 2;
goto L_out;
}
else if ((flt) >= 0x10) {
double flt16 = (flt) / 0x10;
if ((flt16)==(flt)) {
byts[0] = s ? 0xff : 0x7f;
byts[1] = 0xf0;
return sbyts;
}
else {
flt = flt16;
scl = (scl) + 4;
goto L_scale;
}
}
else if ((flt) >= 2) {
flt = (flt) / 2;
scl = (scl) + 1;
goto L_scale;
}
else if (((scl) >= 4) && ((0x10 * flt) < 1)) {
flt = (flt) * 0x10;
scl = (scl) + -4;
goto L_scale;
}
else if ((flt) < 1) {
flt = (flt) * 2;
scl = (scl) + -1;
goto L_scale;
}
else {
flt = -1 + (flt);
goto L_out;
}
}
static char s_integer_byte_collate_M[] = "integer-byte-collate!";
SCM scm_integer_byte_collate_M(byte_vector)
SCM byte_vector;
{
char* bv = get_bytes(byte_vector, 1, s_integer_byte_collate_M);
bv[0] = 0x80^(bv[0]);
return byte_vector;
}
static char s_ieee_byte_collate_M[] = "ieee-byte-collate!";
SCM scm_ieee_byte_collate_M(byte_vector)
SCM byte_vector;
{
char* byv = get_bytes(byte_vector, 4, s_ieee_byte_collate_M);
int byvlen = get_bytes_length(byte_vector);
if (0x80&(byv[0])) {
int idx = -1 + byvlen;
while (!(0 > (idx))) {
byv[idx] = 0xff^(byv[idx]);
idx = -1+(idx);
}
}
else
byv[0] = 0x80^(byv[0]);
return byte_vector;
}
static char s_ieee_byte_decollate_M[] = "ieee-byte-decollate!";
SCM scm_ieee_byte_decollate_M(byte_vector)
SCM byte_vector;
{
char* byv = get_bytes(byte_vector, 4, s_ieee_byte_collate_M);
int byvlen = get_bytes_length(byte_vector);
if (!(0x80&(byv[0]))) {
int idx = -1 + byvlen;
while (!(0 > (idx))) {
byv[idx] = 0xff^(byv[idx]);
idx = -1+(idx);
}
}
else
byv[0] = 0x80^(byv[0]);
return byte_vector;
}
static iproc subr1s[] = {
{s_bytes_to_ieee_float, scm_bytes_to_ieee_float},
{s_bytes_to_ieee_double, scm_bytes_to_ieee_double},
{s_ieee_float_to_bytes, scm_ieee_float_to_bytes},
{s_ieee_double_to_bytes, scm_ieee_double_to_bytes},
{s_integer_byte_collate_M, scm_integer_byte_collate_M},
{s_ieee_byte_collate_M, scm_ieee_byte_collate_M},
{s_ieee_byte_decollate_M, scm_ieee_byte_decollate_M},
{0, 0}};
void init_bytenumb()
{
list_of_0 = cons(INUM0, EOL);
scm_gc_protect(list_of_0);
make_subr(s_bytes_to_integer, tc7_subr_2, scm_bytes_to_integer);
make_subr(s_integer_to_bytes, tc7_subr_2, scm_integer_to_bytes);
init_iprocs(subr1s, tc7_subr_1);
scm_ldstr("\n\
(define (integer-byte-collate byte-vector)\n\
(integer-byte-collate! (bytes-copy byte-vector)))\n\
(define (ieee-byte-collate byte-vector)\n\
(ieee-byte-collate! (bytes-copy byte-vector)))\n\
(define (ieee-byte-decollate byte-vector)\n\
(ieee-byte-decollate! (bytes-copy byte-vector)))\n\
");
/* add_feature("byte-number"); */
}