Added string function.
This commit is contained in:
parent
1d7c99d3df
commit
14831b57f5
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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! */
|
||||
|
|
Reference in New Issue