/* ***************************************************************************** * libg1m/bcd.h -- BCD-encoded numbers manipulation. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * 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 . * * 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 */