109 lines
4.2 KiB
C
109 lines
4.2 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
|
|
|
|
/* ************************************************************************** */
|
|
/* 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. */
|
|
|
|
# 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;
|
|
|
|
/* ************************************************************************** */
|
|
/* 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);
|
|
|
|
# ifdef __cplusplus
|
|
}
|
|
# endif
|
|
#endif /* LIBG1M_BCD_H */
|