Corrected BCD management.
This commit is contained in:
parent
81822777de
commit
d436ce2791
|
@ -37,58 +37,80 @@
|
|||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
# define G1M_BCD_MANTISSA_SIZE 16
|
||||
|
||||
/* Type definition */
|
||||
typedef struct bcd {
|
||||
/* the BCD value itself */
|
||||
unsigned char BCDval[9];
|
||||
/* ************************************************************************** */
|
||||
/* Main type */
|
||||
/* ************************************************************************** */
|
||||
/* libg1m type definition
|
||||
* This is the "unzipped" BCD format. There are several, this is the one libg1m
|
||||
* will always convert to.
|
||||
*
|
||||
* `neg` is whether the number is negative or not.
|
||||
* `exp` is the 10-exponent, between -99 and 99.
|
||||
* `digits` is the number of significant digits in the mantissa.
|
||||
* `spe` is the special bit.
|
||||
* `mant` is the mantissa: unpacked BCD digits (one digit per byte).
|
||||
*
|
||||
* It is advised to use the macros, as some of these could change. */
|
||||
|
||||
/* some 4-bytes alignment stuff */
|
||||
unsigned char _align[3];
|
||||
# define g1m_bcd_has_special(B) ((B)->spe)
|
||||
# define g1m_bcd_is_negative(B) ((B)->neg)
|
||||
typedef struct g1m_bcd_s {
|
||||
int exp, digits;
|
||||
int neg, spe; /* use the macros for these! */
|
||||
char mant[G1M_BCD_MANTISSA_SIZE];
|
||||
} g1m_bcd_t;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* BCD utilities */
|
||||
/* Raw formats */
|
||||
/* ************************************************************************** */
|
||||
/* Arithmetic */
|
||||
int g1m_bcd_is_nonzero(g1m_bcd_t *bcd);
|
||||
|
||||
/* String/BCD */
|
||||
char *g1m_bcdtoa(g1m_bcd_t *bcd);
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Inline BCD utilities */
|
||||
/* ************************************************************************** */
|
||||
/**
|
||||
* g1m_bcd_is_negative:
|
||||
* Quick check.
|
||||
/* CAS BCD -- the old BCD format.
|
||||
*
|
||||
* @arg bcd pointer to the BCD number.
|
||||
* @return a boolean.
|
||||
*/
|
||||
|
||||
static inline int g1m_bcd_is_negative(g1m_bcd_t *bcd)
|
||||
{
|
||||
return (bcd->BCDval[0] >= 0x50);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_bcd_high_bit:
|
||||
* Quick check.
|
||||
* First two nibbles are the integer part, the fourteen that follow are
|
||||
* the decimal part. They are followed by the sign info byte, then with a
|
||||
* BCD exponent (two nibbles).
|
||||
*
|
||||
* @arg bcd pointer to the BCD number.
|
||||
* @return a boolean.
|
||||
*/
|
||||
* The sign info byte is basically the flags of the number.
|
||||
* The negative is two bits/flags (I don't know why).
|
||||
* `g1m_casbcd_pow_neg`, if there, means the power is negative. */
|
||||
|
||||
static inline int g1m_bcd_high_bit(g1m_bcd_t *bcd)
|
||||
{
|
||||
return (bcd->BCDval[0] & 0x80);
|
||||
}
|
||||
# define g1m_casbcd_special 0x80
|
||||
# define g1m_casbcd_negative 0x50
|
||||
# define g1m_casbcd_pow_neg 0x01
|
||||
typedef struct {
|
||||
unsigned char mantissa[8];
|
||||
unsigned char signinfo;
|
||||
unsigned char exponent;
|
||||
} cas_bcd_t;
|
||||
|
||||
/* macros */
|
||||
# define g1m_bcd_is_positive(B) (!g1m_bcd_is_negative(B))
|
||||
# define g1m_bcd_is_zero(B) (!g1m_bcd_is_nonzero(B))
|
||||
# define g1m_bcd_has_complex(B) (g1m_bcd_high_bit(B))
|
||||
/* MCS BCD -- the most recent BCD format.
|
||||
* Only the first 9 bytes are significant.
|
||||
*
|
||||
* The highest bit of the first byte isn't to be considered as part of the
|
||||
* first nibble, it means something else (generally "the number has a complex
|
||||
* part").
|
||||
*
|
||||
* The first three nibbles are the exponent. If it is more than 500, the
|
||||
* number is negative. Its offset is -99.
|
||||
* The other values (from the fourth nibble) are the packed BCD mantissa.
|
||||
* It starts at 10^0. */
|
||||
|
||||
typedef struct bcd {
|
||||
unsigned char BCDval[9];
|
||||
unsigned char _align[3];
|
||||
} mcs_bcd_t;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* Conversion utilities */
|
||||
/* ************************************************************************** */
|
||||
/* From and to MCS BCD. */
|
||||
int g1m_bcd_frommcs(const mcs_bcd_t *raw, g1m_bcd_t *bcd);
|
||||
void g1m_bcd_tomcs(const g1m_bcd_t *bcd, mcs_bcd_t *raw);
|
||||
|
||||
/* From and to CAS BCD. */
|
||||
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);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#ifndef LIBG1M_FORMAT_MCSFILE_H
|
||||
# define LIBG1M_FORMAT_MCSFILE_H
|
||||
# include <libg1m/format/mcs.h>
|
||||
# include <libg1m/bcd.h>
|
||||
# pragma pack(1)
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/* *****************************************************************************
|
||||
* libg1m/internals/bcd.h -- the libg1m BCD internal helpers.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#ifndef LIBG1M_INTERNALS_BCD_H
|
||||
# define LIBG1M_INTERNALS_BCD_H
|
||||
# include <libg1m/bcd.h>
|
||||
# include <string.h>
|
||||
# define upr(N) ((bytes[(N)] & 0xf0) >> 4)
|
||||
# define lwr(N) (bytes[(N)] & 0xf)
|
||||
|
||||
int g1m_bcd_get_exponent(struct bcd *bcd);
|
||||
int g1m_bcd_get_exponent_neg(struct bcd *bcd, int *neg);
|
||||
|
||||
#endif /* LIBG1M_INTERNALS_BCD_H */
|
|
@ -0,0 +1,94 @@
|
|||
/* *****************************************************************************
|
||||
* bcd/cas.c -- make a libg1m BCD out of an CAS BCD number.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#define upr(N) ((bytes[(N)] & 0xf0) >> 4)
|
||||
#define lwr(N) (bytes[(N)] & 0xf)
|
||||
|
||||
/**
|
||||
* g1m_bcd_fromcas:
|
||||
* Make a libg1m BCD out of an CAS BCD number.
|
||||
*
|
||||
* @arg raw the raw BCD.
|
||||
* @arg dest the not raw BCD.
|
||||
* @return the special bit, for simplicity.
|
||||
*/
|
||||
|
||||
int g1m_bcd_fromcas(const cas_bcd_t *raw, g1m_bcd_t *bcd)
|
||||
{
|
||||
const unsigned char *bytes = raw->mantissa;
|
||||
|
||||
/* get the exponent and sign */
|
||||
bcd->digits = 15;
|
||||
bcd->exp = (raw->exponent >> 4) * 10 + (raw->exponent & 0x0F);
|
||||
if (raw->signinfo & g1m_casbcd_pow_neg)
|
||||
bcd->exp = -bcd->exp;
|
||||
|
||||
/* get the mantissa */
|
||||
bcd->mant[0] = lwr(0);
|
||||
bcd->mant[1] = upr(1);
|
||||
bcd->mant[2] = lwr(1);
|
||||
bcd->mant[3] = upr(2);
|
||||
bcd->mant[4] = lwr(2);
|
||||
bcd->mant[5] = upr(3);
|
||||
bcd->mant[6] = lwr(3);
|
||||
bcd->mant[7] = upr(4);
|
||||
bcd->mant[8] = lwr(4);
|
||||
bcd->mant[9] = upr(5);
|
||||
bcd->mant[10] = lwr(5);
|
||||
bcd->mant[11] = upr(6);
|
||||
bcd->mant[12] = lwr(6);
|
||||
bcd->mant[13] = upr(7);
|
||||
bcd->mant[14] = lwr(7);
|
||||
|
||||
/* set the special things and return */
|
||||
bcd->neg = raw->signinfo & g1m_casbcd_negative;
|
||||
bcd->spe = raw->signinfo & g1m_casbcd_special;
|
||||
return (bcd->spe);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_bcd_tocas:
|
||||
* Make an CAS BCD number out of a libg1m BCD number.
|
||||
*
|
||||
* @arg bcd the not raw BCD.
|
||||
* @arg raw the raw BCD.
|
||||
*/
|
||||
|
||||
void g1m_bcd_tocas(const g1m_bcd_t *bcd, cas_bcd_t *raw)
|
||||
{
|
||||
/* put the exponent */
|
||||
div_t d = div(abs(bcd->exp), 10);
|
||||
raw->exponent = (d.quot << 4) | d.rem;
|
||||
|
||||
/* put the mantissa */
|
||||
raw->mantissa[0] = bcd->mant[0];
|
||||
raw->mantissa[1] = (bcd->mant[1] << 4) | bcd->mant[2];
|
||||
raw->mantissa[2] = (bcd->mant[3] << 4) | bcd->mant[4];
|
||||
raw->mantissa[3] = (bcd->mant[5] << 4) | bcd->mant[6];
|
||||
raw->mantissa[4] = (bcd->mant[7] << 4) | bcd->mant[8];
|
||||
raw->mantissa[5] = (bcd->mant[9] << 4) | bcd->mant[10];
|
||||
raw->mantissa[6] = (bcd->mant[11] << 4) | bcd->mant[12];
|
||||
raw->mantissa[7] = (bcd->mant[13] << 4) | bcd->mant[14];
|
||||
|
||||
/* put the flags */
|
||||
raw->signinfo = 0;
|
||||
if (bcd->exp < 0) raw->signinfo |= g1m_casbcd_pow_neg;
|
||||
if (bcd->neg) raw->signinfo |= g1m_casbcd_negative;
|
||||
if (bcd->spe) raw->signinfo |= g1m_casbcd_special;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/* *****************************************************************************
|
||||
* bcd/get_exponent.c -- get the exponent out of a BCD-encoded number.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <libg1m/internals/bcd.h>
|
||||
|
||||
/**
|
||||
* g1m_bcd_get_exponent:
|
||||
* Get exponent.
|
||||
*/
|
||||
|
||||
int g1m_bcd_get_exponent(struct bcd *bcd)
|
||||
{
|
||||
unsigned char *bytes = bcd->BCDval;
|
||||
|
||||
int exp = (upr(0) & 0x7) * 100 + lwr(0) * 10 + upr(1);
|
||||
return ((exp % 500) - 99);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_bcd_get_exponent_neg:
|
||||
* Get exponent and if it is negative.
|
||||
*/
|
||||
|
||||
int g1m_bcd_get_exponent_neg(struct bcd *bcd, int *neg)
|
||||
{
|
||||
unsigned char *bytes = bcd->BCDval;
|
||||
|
||||
*neg = 0;
|
||||
int exp = (upr(0) & 0x7) * 100 + lwr(0) * 10 + upr(1);
|
||||
if (exp >= 500) exp -= 500, *neg = 1;
|
||||
return (exp - 99);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* *****************************************************************************
|
||||
* bcd/is_zero.c -- check if a BCD is zero or not.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <libg1m/internals/bcd.h>
|
||||
|
||||
/**
|
||||
* g1m_bcd_is_nonzero:
|
||||
* Check if a BCD is zero.
|
||||
*
|
||||
* @arg bcd pointer to the bcd.
|
||||
* @return true or false.
|
||||
*/
|
||||
|
||||
int g1m_bcd_is_nonzero(struct bcd *bcd)
|
||||
{
|
||||
static struct bcd ref = {.BCDval = {}};
|
||||
unsigned char *bytes = bcd->BCDval;
|
||||
|
||||
return (lwr(1) | memcmp(&bytes[2], &ref.BCDval[2], 7));
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* *****************************************************************************
|
||||
* bcd/mcs.c -- make a libg1m BCD out of an MCS BCD number.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#define upr(N) ((bytes[(N)] & 0xf0) >> 4)
|
||||
#define lwr(N) (bytes[(N)] & 0xf)
|
||||
|
||||
/**
|
||||
* g1m_bcd_frommcs:
|
||||
* Make a libg1m BCD out of an MCS BCD number.
|
||||
*
|
||||
* @arg raw the raw BCD.
|
||||
* @arg dest the not raw BCD.
|
||||
* @return the special bit, for simplicity.
|
||||
*/
|
||||
|
||||
int g1m_bcd_frommcs(const mcs_bcd_t *raw, g1m_bcd_t *bcd)
|
||||
{
|
||||
const unsigned char *bytes = raw->BCDval;
|
||||
|
||||
/* get the 10-exponent */
|
||||
bcd->digits = 15;
|
||||
bcd->spe = upr(0) & 0x8;
|
||||
bcd->exp = (upr(0) & 7) * 100 + lwr(0) * 10 + upr(1);
|
||||
|
||||
/* check the negative number, correct the exponent */
|
||||
bcd->neg = 0;
|
||||
if (bcd->exp >= 500) bcd->exp -= 500, bcd->neg = 1;
|
||||
bcd->exp -= 99;
|
||||
|
||||
/* get the mantissa */
|
||||
bcd->mant[0] = lwr(1);
|
||||
bcd->mant[1] = upr(2);
|
||||
bcd->mant[2] = lwr(2);
|
||||
bcd->mant[3] = upr(3);
|
||||
bcd->mant[4] = lwr(3);
|
||||
bcd->mant[5] = upr(4);
|
||||
bcd->mant[6] = lwr(4);
|
||||
bcd->mant[7] = upr(5);
|
||||
bcd->mant[8] = lwr(5);
|
||||
bcd->mant[9] = upr(6);
|
||||
bcd->mant[10] = lwr(6);
|
||||
bcd->mant[11] = upr(7);
|
||||
bcd->mant[12] = lwr(7);
|
||||
bcd->mant[13] = upr(8);
|
||||
bcd->mant[14] = lwr(8);
|
||||
|
||||
/* return the special bit */
|
||||
return (bcd->spe);
|
||||
}
|
||||
|
||||
/**
|
||||
* g1m_bcd_tomcs:
|
||||
* Make an MCS BCD number out of a libg1m BCD number.
|
||||
*
|
||||
* @arg bcd the not raw BCD.
|
||||
* @arg raw the raw BCD.
|
||||
*/
|
||||
|
||||
void g1m_bcd_tomcs(const g1m_bcd_t *bcd, mcs_bcd_t *raw)
|
||||
{
|
||||
int exp = bcd->exp + 99;
|
||||
if (bcd->neg) exp += 500;
|
||||
|
||||
/* put the exponent (and first digit of the mantissa) */
|
||||
div_t c = div(exp, 100);
|
||||
div_t d = div(c.rem, 10);
|
||||
raw->BCDval[0] = (c.quot << 4) | d.quot | (!!bcd->spe << 7);
|
||||
raw->BCDval[1] = (d.rem << 4) | bcd->mant[0];
|
||||
|
||||
/* put the mantissa */
|
||||
raw->BCDval[2] = (bcd->mant[1] << 4) | bcd->mant[2];
|
||||
raw->BCDval[3] = (bcd->mant[3] << 4) | bcd->mant[4];
|
||||
raw->BCDval[4] = (bcd->mant[5] << 4) | bcd->mant[6];
|
||||
raw->BCDval[5] = (bcd->mant[7] << 4) | bcd->mant[8];
|
||||
raw->BCDval[6] = (bcd->mant[9] << 4) | bcd->mant[10];
|
||||
raw->BCDval[7] = (bcd->mant[11] << 4) | bcd->mant[12];
|
||||
raw->BCDval[8] = (bcd->mant[13] << 4) | bcd->mant[14];
|
||||
|
||||
/* set the align zone */
|
||||
raw->_align[0] = 0;
|
||||
raw->_align[1] = 0;
|
||||
raw->_align[2] = 0;
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/* *****************************************************************************
|
||||
* bcd/to_ascii.c -- make an ASCII-encoded string out of a BCD-encoded number.
|
||||
* 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/>.
|
||||
* ************************************************************************** */
|
||||
#include <libg1m/internals.h>
|
||||
#include <libg1m/internals/bcd.h>
|
||||
#define VISIBLE_PRECISION 5
|
||||
|
||||
/**
|
||||
* g1m_bcdtoa:
|
||||
* Simple BCD to string function.
|
||||
*
|
||||
* @arg bcd The BCD number.
|
||||
* @return The allocated string.
|
||||
*/
|
||||
|
||||
char *g1m_bcdtoa(struct bcd *bcd)
|
||||
{
|
||||
char buf[50], *p = buf;
|
||||
unsigned char *bytes = bcd->BCDval;
|
||||
|
||||
/* get the exponent */
|
||||
int neg = 0;
|
||||
int exp = g1m_bcd_get_exponent_neg(bcd, &neg);
|
||||
if (neg) *p++ = '-';
|
||||
|
||||
/* get the mantissa */
|
||||
char mant[15];
|
||||
for (int i = 0; i < 15; i += 2)
|
||||
mant[i] = lwr(i / 2 + 1);
|
||||
for (int i = 1; i < 15; i += 2)
|
||||
mant[i] = upr(i / 2 + 2);
|
||||
|
||||
/* calculate number of significant digits */
|
||||
int signif;
|
||||
for (signif = 15; signif && !mant[signif - 1]; signif--);
|
||||
if (!signif) exp = 0;
|
||||
|
||||
/* put integer part */
|
||||
int num = 0;
|
||||
if (exp > 0) {
|
||||
while (exp > 0 && signif) {
|
||||
exp--;
|
||||
signif--;
|
||||
*p++ = mant[num++] + '0';
|
||||
}
|
||||
if (exp > 0 && exp < VISIBLE_PRECISION) while (exp) {
|
||||
exp--;
|
||||
*p++ = '0';
|
||||
}
|
||||
} else
|
||||
*p++ = '0';
|
||||
|
||||
/* put decimal part */
|
||||
if (signif) {
|
||||
*p++ = '.';
|
||||
/* put some zeroes */
|
||||
if (exp < 0 && exp > -VISIBLE_PRECISION) while (exp) {
|
||||
exp++;
|
||||
*p++ = '0';
|
||||
}
|
||||
/* put the numbers */
|
||||
while (signif--)
|
||||
*p++ = mant[num++] + '0';
|
||||
}
|
||||
|
||||
/* put exponent */
|
||||
if (exp) {
|
||||
*p++ = '^';
|
||||
int exp_neg = exp < 0;
|
||||
if (exp_neg) {
|
||||
*p++ = '(';
|
||||
*p++ = '-';
|
||||
exp = -exp;
|
||||
}
|
||||
int eprec = 1000;
|
||||
while (exp < eprec)
|
||||
eprec /= 10;
|
||||
while (eprec) {
|
||||
*p++ = exp / eprec + '0';
|
||||
exp %= eprec;
|
||||
eprec /= 10;
|
||||
}
|
||||
if (exp_neg) *p++ = ')';
|
||||
}
|
||||
|
||||
/* put string end */
|
||||
*p = 0;
|
||||
|
||||
/* duplicate and send to user */
|
||||
return (strdup(buf));
|
||||
}
|
|
@ -113,8 +113,7 @@ void g1m_free_mcs(g1m_t *handle)
|
|||
/* free the file if exists */
|
||||
if (files[i]) g1m_free_mcsfile(files[i]);
|
||||
}
|
||||
free(files);
|
||||
handle->files = NULL;
|
||||
free(handle->files); handle->files = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
119
src/decode/mcs.c
119
src/decode/mcs.c
|
@ -173,25 +173,21 @@ static int mcs_decode_spreadsheet(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
/* check if used */
|
||||
if (*rd & bit) {
|
||||
/* get cell */
|
||||
DREAD(cell, bcd)
|
||||
g1m_bcd_t cell;
|
||||
DREAD(rawcell, bcd)
|
||||
g1m_bcd_frommcs(&rawcell, &cell);
|
||||
|
||||
/* store it */
|
||||
cells[c * 1000 + i] = (g1m_mcs_cell_t){
|
||||
.used = 1,
|
||||
.real = cell,
|
||||
.imgn = {}
|
||||
.imgn = (g1m_bcd_t){}
|
||||
};
|
||||
|
||||
/* check things (max row, max col, cells count) */
|
||||
rows = max(rows, i);
|
||||
cols = c;
|
||||
cells_count++;
|
||||
|
||||
/* log it */
|
||||
char *bcd_string = g1m_bcdtoa(&cell);
|
||||
log_info("[%" PRIuFAST32 ", %" PRIuFAST32 "] contains '%s'.",
|
||||
c, i, bcd_string);
|
||||
free(bcd_string);
|
||||
}
|
||||
|
||||
/* iterate bit and rd */
|
||||
|
@ -262,26 +258,28 @@ static int mcs_decode_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
size -= sizeof(struct mcs_listheader);
|
||||
|
||||
/* make tabs */
|
||||
size_t elsize = sizeof(struct bcd) * elcount;
|
||||
struct bcd real[elcount];
|
||||
struct bcd imgn[elcount];
|
||||
|
||||
g1m_bcd_t real[elcount], imgn[elcount];
|
||||
if (elcount) {
|
||||
/* browse real elements */
|
||||
log_info("Browsing %" PRIuFAST16 " list elements", elcount);
|
||||
READ(&real, elsize)
|
||||
size -= elsize;
|
||||
|
||||
/* check if there is one imaginary number */
|
||||
int one_imgn = 0;
|
||||
for (uint_fast16_t i = 0; i < elcount && !one_imgn; i++)
|
||||
one_imgn |= g1m_bcd_has_complex(&real[i]);
|
||||
mcs_bcd_t tab[elcount];
|
||||
/* read the real parts */
|
||||
size_t elsize = sizeof(mcs_bcd_t) * elcount;
|
||||
size -= elsize; {
|
||||
/* read reals */
|
||||
READ(tab, elsize)
|
||||
|
||||
/* browse imaginary elements */
|
||||
/* convert them */
|
||||
for (uint_fast16_t i = 0; i < elsize; i++)
|
||||
one_imgn |= g1m_bcd_frommcs(&tab[elcount], &real[elcount]);
|
||||
}
|
||||
|
||||
/* read the imaginary parts */
|
||||
if (one_imgn) {
|
||||
log_info("They have complex parts!");
|
||||
size_t toread = min(size, elsize);
|
||||
READ(&imgn, toread)
|
||||
READ(tab, elsize)
|
||||
|
||||
/* convert */
|
||||
for (uint_fast16_t i = 0; i < elsize; i++)
|
||||
g1m_bcd_frommcs(&tab[elcount], &imgn[elcount]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,28 +296,14 @@ static int mcs_decode_list(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
|
||||
/* main copying loop */
|
||||
for (uint_fast32_t y = 0; y < elcount; y++) {
|
||||
int has_complex = g1m_bcd_has_complex(&real[y]);
|
||||
|
||||
/* log */
|
||||
#if LOGLEVEL <= ll_info
|
||||
char *real_string = g1m_bcdtoa(&real[y]);
|
||||
if (!has_complex)
|
||||
log_info("Cell #%" PRIuFAST32 " is (%s).", y, real_string);
|
||||
else {
|
||||
char *imgn_string = g1m_bcdtoa(&imgn[y]);
|
||||
log_info("Cell #%" PRIuFAST32 " is (%s)+(%s)i.",
|
||||
y, real_string, imgn_string);
|
||||
free(imgn_string);
|
||||
}
|
||||
free(real_string);
|
||||
#endif
|
||||
int has_complex = g1m_bcd_has_special(&real[y]);
|
||||
|
||||
/* prepare index and store */
|
||||
tab[y] = &rws[y];
|
||||
tab[y][0] = (g1m_mcs_cell_t){
|
||||
.used = 1,
|
||||
.real = real[y],
|
||||
.imgn = has_complex ? imgn[y] : (struct bcd){}
|
||||
.imgn = has_complex ? imgn[y] : (g1m_bcd_t){}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -379,8 +363,9 @@ static int mcs_decode_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
/* read squares */
|
||||
for (uint_fast32_t x = 0; x < w; x++) {
|
||||
/* read the cell */
|
||||
GDREAD(cell, bcd)
|
||||
one_imgn |= g1m_bcd_has_complex(&cell);
|
||||
g1m_bcd_t cell;
|
||||
GDREAD(rawcell, bcd)
|
||||
one_imgn |= g1m_bcd_frommcs(&rawcell, &cell);
|
||||
|
||||
/* store it */
|
||||
tab[y][x] = (g1m_mcs_cell_t){
|
||||
|
@ -395,10 +380,12 @@ static int mcs_decode_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
if (one_imgn) {
|
||||
for (uint_fast32_t y = 0; y < h; y++)
|
||||
for (uint_fast32_t x = 0; x < w; x++) {
|
||||
GDREAD(cell, bcd)
|
||||
|
||||
if (g1m_bcd_has_complex(&tab[y][x].real))
|
||||
GDREAD(rawcell, bcd)
|
||||
if (tab[y][x].real.spe) {
|
||||
g1m_bcd_t cell;
|
||||
g1m_bcd_frommcs(&rawcell, &cell);
|
||||
tab[y][x].imgn = cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,25 +393,6 @@ static int mcs_decode_matrix(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
handle->cells = tab;
|
||||
}
|
||||
|
||||
#if LOGLEVEL <= ll_info
|
||||
for (uint_fast32_t y = 0; y < h; y++)
|
||||
for (uint_fast32_t x = 0; x < w; x++) {
|
||||
g1m_mcs_cell_t *cell = &tab[y][x];
|
||||
|
||||
char *real_string = g1m_bcdtoa(&cell->real);
|
||||
if (!g1m_bcd_has_complex(&cell->real))
|
||||
log_info("[%" PRIuFAST32 "][%" PRIuFAST32 "] (%s).",
|
||||
x, y, real_string);
|
||||
else {
|
||||
char *imgn_string = g1m_bcdtoa(&cell->imgn);
|
||||
log_info("[%" PRIuFAST32 "][%" PRIuFAST32 "] (%s)+(%s)i.",
|
||||
x, y, real_string, imgn_string);
|
||||
free(imgn_string);
|
||||
}
|
||||
free(real_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no error */
|
||||
return (0);
|
||||
|
||||
|
@ -569,27 +537,6 @@ static int mcs_decode_alphamem(g1m_mcsfile_t *handle, g1m_buffer_t *buffer,
|
|||
size_t tocopy = length - length % sizeof(g1m_mcs_cell_t);
|
||||
memcpy(handle->vars, buf, tocopy);
|
||||
|
||||
/* log */
|
||||
#if LOGLEVEL <= ll_inf
|
||||
for (int i = 0; i < 29; i++) {
|
||||
const char *var_name = (const char*[]){
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"Theta", "r", "Ans"
|
||||
}[i];
|
||||
|
||||
char *real_string = g1m_bcdtoa(&handle->vars[i].real);
|
||||
if (!g1m_bcd_has_complex(&handle->vars[i].real))
|
||||
log_info("%s is (%s).", var_name, real_string);
|
||||
else {
|
||||
char *imgn_string = g1m_bcdtoa(&handle->vars[i].imgn);
|
||||
log_info("%s is (%s)+(%s)i.", var_name, real_string, imgn_string);
|
||||
free(imgn_string);
|
||||
}
|
||||
free(real_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no problem, woop woop */
|
||||
return (0);
|
||||
}
|
||||
|
@ -776,7 +723,7 @@ fail:
|
|||
int g1m_decode_mcsfile_data(g1m_mcsfile_t **handle,
|
||||
const g1m_mcshead_t *head, const unsigned char *data, size_t size)
|
||||
{
|
||||
unsigned char *p = data;
|
||||
const unsigned char *p = data;
|
||||
g1m_buffer_t buffer = {
|
||||
.cookie = p,
|
||||
.read = g1m_membuffer_read
|
||||
|
|
Reference in New Issue