cake
/
libg1m
Archived
1
0
Fork 0

Added string function.

This commit is contained in:
Thomas Touhey 2017-02-28 22:22:56 +01:00
parent 1d7c99d3df
commit 14831b57f5
4 changed files with 178 additions and 11 deletions

View File

@ -28,6 +28,16 @@
extern "C" {
# endif
# define G1M_BCD_MANTISSA_SIZE 16
# define G1M_BCD_EXPMIN -99
# define G1M_BCD_EXPMAX 99
/* String constants; here are some examples:
* - 1.23456789ABCDEFe99
* - -0.0000123456789ABCDEF
* - 123456789ABCDEF0000000 */
# define G1M_BCD_GOODBUFSIZE \
(2 + G1M_BCD_MANTISSA_SIZE + 4 + 2 + 1)
/* ************************************************************************** */
/* Main type */
@ -40,16 +50,20 @@ extern "C" {
* `exp` is the 10-exponent, between -99 and 99.
* `mant` is the mantissa: unpacked BCD digits (one digit per byte).
*
* To interact the flags, it is advised to use the g1m_bcd_* macros, as some
* of them could change. */
* The first digit of the mantissa is the integer part, the others are
* the decimal part.
*
* To interact the flags or the exponent, it is advised to use the g1m_bcd_*
* macros, as some of them could change. */
# define g1m_bcdflag_neg 0x80
# define g1m_bcdflag_spe 0x40
# define g1m_bcdflag_spe 0x80
# define g1m_bcdflag_neg 0x40
# define g1m_bcdmask_pre 0x3F
# define g1m_bcd_has_special(B) ((B)->flags & g1m_bcdflag_spe)
# define g1m_bcd_is_negative(B) ((B)->flags & g1m_bcdflag_neg)
# define g1m_bcd_precision(B) ((B)->flags & g1m_bcdmask_pre)
# define g1m_bcd_exponent(B) ((B)->exp)
# define g1m_make_bcdflags(SPE, NEG, PREC) \
(((SPE) << 7) | ((NEG) << 6) | (PREC))
@ -108,6 +122,9 @@ void g1m_bcd_tomcs(const g1m_bcd_t *bcd, mcs_bcd_t *raw);
int g1m_bcd_fromcas(const cas_bcd_t *raw, g1m_bcd_t *bcd);
void g1m_bcd_tocas(const g1m_bcd_t *bcd, cas_bcd_t *raw);
/* Make a string out of a BCD */
size_t g1m_bcdtoa(const g1m_bcd_t *bcd, char *buf, size_t len);
# ifdef __cplusplus
}
# endif

View File

@ -17,8 +17,8 @@
* along with libg1m; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libg1m/internals.h>
#define upr(N) ((bytes[(N)] & 0xf0) >> 4)
#define lwr(N) (bytes[(N)] & 0xf)
#define upr(N) (bytes[(N)] >> 4)
#define lwr(N) (bytes[(N)] & 15)
/**
* g1m_bcd_frommcs:
@ -39,7 +39,7 @@ int g1m_bcd_frommcs(const mcs_bcd_t *raw, g1m_bcd_t *bcd)
bcd->exp = (char)(exp - 99);
/* set the flags */
bcd->flags = g1m_make_bcdflags(bytes[0] & 0x80 >> 7, neg, 15);
bcd->flags = g1m_make_bcdflags((bytes[0] & 0x80) >> 7, neg, 15);
/* get the mantissa */
bcd->mant[0] = lwr(1);

137
src/bcd/str.c Normal file
View File

@ -0,0 +1,137 @@
/* *****************************************************************************
* bcd/str.c -- make a string out of a libg1m BCD.
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libg1m.
* libg1m 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.0 of the License,
* or (at your option) any later version.
*
* libg1m 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 libg1m; if not, see <http://www.gnu.org/licenses/>.
*
* These functions are experimental!
* I wrote most of this while comparing the results to what I wanted.
* If you think you can write a clean equivalent of this, while understanding
* the theory behind what you do, please try! :)
* ************************************************************************** */
#include <libg1m/internals.h>
/**
* getsize:
* Get the size.
*
* @arg exp the exponent.
* @arg neg whether the number is negative or not.
* @arg offset the offset.
* @arg digits the number of digits.
* @return the size.
*/
static size_t getsize(int exp, int neg, int offset, int digits)
{
size_t sz = digits;
if (neg)
sz++;
if (offset + digits < 0)
sz += -digits - offset; /* zeroes */
if (offset + digits > 0)
sz++; /* point */
if (offset >= 0)
sz += 1 /* leading zero */ + offset;
if (exp) {
sz++; /* e */
if (exp < 0) sz += 1;
int eexp = abs(exp);
if (eexp >= 100) sz += 3;
else if (eexp >= 10) sz += 2;
else sz += 1;
}
return (sz);
}
/**
* g1m_bcdtoa:
* Make a string out of a BCD number.
*
* If the buffer is not big enough, the number will not be written down.
* Will terminate the buffer if the string is written.
*
* @arg bcd the BCD.
* @arg buf the buffer.
* @arg len the length.
* @return the required length if needed, otherwise, zero.
*/
size_t g1m_bcdtoa(const g1m_bcd_t *bcd, char *buf, size_t len)
{
/* get base digit */
int exp = g1m_bcd_exponent(bcd), offset = 0;
int leftdigits = g1m_bcd_precision(bcd);
const char *digits = bcd->mant;
for (; leftdigits > 0; leftdigits--) {
if (*digits) break;
exp--;
digits++;
}
/* get number of digits, check if zero */
for (; leftdigits && !digits[leftdigits - 1]; leftdigits--);
if (!leftdigits) {
int l = (len >= 2) ? 0 : 2;
memcpy(buf, "0", 2 - l);
return (len);
}
/* try to play with the settings to make a more acceptable output */
int neg = !!g1m_bcd_is_negative(bcd);
int acceptable_alt = max(0, 5 - leftdigits);
if (-acceptable_alt < exp && exp <= 5) {
offset -= exp;
exp = 0;
}
if (offset >= 0) {
exp -= offset + 1;
offset = -1;
}
/* calculate the size */
size_t sz = getsize(exp, neg, offset, leftdigits);
/* check if there's enough space in the buffer */
if (sz > len) return (sz);
/* then fill */
int origdigits = leftdigits;
if (neg)
*buf++ = '-';
for (; leftdigits && offset < 0; offset++, leftdigits--)
*buf++ = *digits++ + '0';
for (; offset < 0; offset++)
*buf++ = '0';
if (leftdigits == origdigits)
*buf++ = '0';
if (offset > 0 || leftdigits)
*buf++ = '.';
for (; offset > 0; offset--)
*buf++ = '0';
while (leftdigits--)
*buf++ = *digits++ + '0';
if (exp) {
*buf++ = 'e';
if (exp < 0) { *buf++ = '-'; exp = -exp; }
if (exp >= 100) *buf++ = exp / 100 + '0';
if (exp >= 10) *buf++ = (exp % 100) / 10 + '0';
*buf++ = exp % 10 + '0';
}
*buf = 0;
/* it's done! */
return (0);
}

View File

@ -55,8 +55,8 @@ int g1m_decode_mcs_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
READ(tab, elsize)
/* convert them */
for (uint_fast16_t i = 0; i < elsize; i++)
one_imgn |= g1m_bcd_frommcs(&tab[elcount], &real[elcount]);
for (uint_fast16_t i = 0; i < elcount; i++)
one_imgn |= g1m_bcd_frommcs(&tab[i], &real[i]);
}
/* read the imaginary parts */
@ -64,8 +64,8 @@ int g1m_decode_mcs_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
READ(tab, elsize)
/* convert */
for (uint_fast16_t i = 0; i < elsize; i++)
g1m_bcd_frommcs(&tab[elcount], &imgn[elcount]);
for (uint_fast16_t i = 0; i < elcount; i++)
g1m_bcd_frommcs(&tab[i], &imgn[i]);
}
}
@ -74,6 +74,10 @@ int g1m_decode_mcs_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
handle->columns = 1;
handle->cells = NULL;
if (elcount) {
#if LOGLEVEL >= ll_info
char rbuf[G1M_BCD_GOODBUFSIZE], ibuf[G1M_BCD_GOODBUFSIZE];
#endif
/* allocate final tab */
g1m_mcs_cell_t **tab = malloc(sizeof(g1m_mcs_cell_t*) * elcount);
if (!tab) return (g1m_error_alloc);
@ -91,6 +95,15 @@ int g1m_decode_mcs_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
.real = real[y],
.imgn = has_complex ? imgn[y] : (g1m_bcd_t){}
};
#if LOGLEVEL >= ll_info
g1m_bcdtoa(&tab[y][0].real, rbuf, G1M_BCD_GOODBUFSIZE);
if (has_complex) {
g1m_bcdtoa(&tab[y][0].imgn, ibuf, G1M_BCD_GOODBUFSIZE);
log_info("[%" PRIuFAST32 "] %si + %s", y, ibuf, rbuf);
} else
log_info("[%" PRIuFAST32 "] %s", y, rbuf);
#endif
}
/* don't forget your baguette! */