div10(), div100(), div1000()
struct div_result_i32 {
int32_t quo; // quotient
int16_t rem; // remainder
uint8_t b_neg; // true if negative
uint8_t digits_rem; // digits of remainder
};
div_result_i32 div10(int32_t val);
div_result_i32 div100(int32_t val);
div_result_i32 div1000(int32_t val);
In some cases, sensor values multiplied by 100 are passed as uint16_t
type, but on microcontrollers without division circuits, calculation processing takes considerable time. Therefore, calculations are performed using approximate calculations and corrections with addition, subtraction, multiplication, and bit shifts.
Pass the value to be calculated in val
, the variable to store the remainder in rem
, and the variable to store the sign in neg
.
The return value is the quotient (always positive), rem
contains the remainder (always positive), and neg
stores true
if negative.
Due to algorithm constraints (digit overflow), the calculable value range is limited for div100()
and div1000()
. div100()
supports values from -99999 to 99999, and div1000()
supports values from -999999 to 999999.
Approximate formula to obtain the quotient
div100()
int dv = val * 1311 >> 17;
div1000()
int dv = val * 131 >> 17;
Example usage
auto d1 = div100(sns_val.u16temp_object);
auto d2 = div100(sns_val.u16temp_object);
Serial
<< crlf << format("..Object = %c%2d.%02d"
, d1.b_neg ? '-' : '+', d1.quo, d1.rem)
<< format(" Ambient = %c%2d.%02d"
, d2.b_neg ? '-' : '+', d2.quo, d2.rem);
Calculation speed
About one-tenth of the time.
Output of results
// Conversion options
struct DIVFMT {
static const int STD = 0; // displays with minimal digits (no padding, no positive sign)
static const int PAD_ZERO = 1; // set padding character as '0' instead of ' '.
static const int SIGN_PLUS = 2; // put '+' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_PLUS = 3; // PAD_ZERO & SIGN_PLUS
static const int SIGN_SPACE = 4; // put ' ' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_SPACE = 5; // PAD_ZERO & SIGN_SPACE
};
// Class to store string conversion results
class _div_chars {
...
const char* begin() const {...}
const char* end() const {...}
const char* c_str() const { return begin(); }
operator const char*() const { return begin(); }
};
// format() method
_div_chars div_result_i32::format(
int dig_quo = 0, uint32_t opt = DIVFMT::STD) const;
// Implementation of interface to Serial
template <class D> class stream {
...
inline D& operator << (const mwx::_div_chars&& divc);
inline D& operator << (const mwx::div_result_i32&&);
inline D& operator << (const mwx::div_result_i32&);
};
The div_result_i32
class that stores the division result has a format()
method to obtain a _div_chars
class object. The _div_chars
class object contains a string buffer and provides methods to access the string buffer as const char*
. Also, the <<
operator for the Serial
object is implemented.
The first parameter dig_quo
of the format()
method specifies the number of output digits (excluding the sign). If the output digits are insufficient (below), it is filled with spaces or 0
. The second parameter opt
specifies the format.
opt parameter | Description |
---|---|
DIVFMT::STD | Standard output, fills insufficient digits with spaces, and adds - only for negative values. |
DIVFMT::PAD_ZERO | Fills insufficient digits with 0 . |
DIVFMT::SIGN_PLUS | Adds + sign for positive values as well. |
DIVFMT::PAD_ZERO_SIGN_PLUS | Fills insufficient digits with 0 and adds + sign for positive values. |
DIVFMT::SIGN_SPACE | Adds a space sign instead of + for positive values. |
DIVFMT::PAD_ZERO_SIGN_SPACE | Fills insufficient digits with 0 and adds a space sign instead of + for positive values. |
Example
//// Direct output from div_result_i32 object
Serial << div100(-1234) << crlf;
// Result: -12.34
//// Output with 3 digits
Serial << div100(3456).format(3, DIVFMT::PAD_ZERO_SIGN_PLUE) << crlf;
// Result: +034.56
//// Use c_str() to get const char*
char str1[128];
auto x = div100(-5678);
mwx_snprintf(str1, 16, "VAL=%s", x.format.c_str()); // const char*
Serial << str1;
// Result: VAL=-56.78
Background
In TWELITE BLUE/RED, division is a costly operation, so a division algorithm with limited purposes was added.
Within the library, some sensor values such as temperature and humidity are represented using values multiplied by 100 (e.g., 25.12℃ as 2512), so a simple procedure to obtain the quotient and remainder when divided by 100 was defined.
dev_result_i32::format()
is provided to avoid complexity when formatting output.