cake
/
libg1m
Archived
1
0
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libg1m/include/libg1m/bcd.h

136 lines
5.0 KiB
C

/* *****************************************************************************
* libg1m/bcd.h -- BCD-encoded numbers manipulation.
* 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/>.
*
* BCD are the main number format CASIO uses in its calculators.
* This format has the huge advantage to make 0.1 + 0.2 and 0.3 equal.
*
* There are several raw BCD formats, libg1m offers conversion to its own
* format, easier to read and write (but not optimized for storing).
* ************************************************************************** */
#ifndef LIBG1M_BCD_H
# define LIBG1M_BCD_H
# ifdef __cplusplus
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 */
/* ************************************************************************** */
/* libg1m type definition
* This is the "unzipped" BCD format. There are several, this is the one libg1m
* will always convert to.
*
* `flags` is the flags (negative, special, precision) of the BCD.
* `exp` is the 10-exponent, between -99 and 99.
* `mant` is the mantissa: unpacked BCD digits (one digit per byte).
*
* 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_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))
typedef struct g1m_bcd_s {
unsigned char flags; char exp;
char mant[G1M_BCD_MANTISSA_SIZE];
} g1m_bcd_t;
/* ************************************************************************** */
/* Raw formats */
/* ************************************************************************** */
/* CAS BCD -- the old BCD format.
*
* 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).
*
* 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. */
# 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;
/* 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);
/* From and to C-double */
void g1m_bcd_fromdouble(double dbl, g1m_bcd_t *bcd);
double g1m_bcd_todouble(const g1m_bcd_t *bcd);
/* Make a string out of a BCD */
size_t g1m_bcdtoa(const g1m_bcd_t *bcd, char *buf, size_t len);
# ifdef __cplusplus
}
# endif
#endif /* LIBG1M_BCD_H */