div100()

Fast divisions by 10, 100 or 1000.

The quotient divided by 10, 100 or 1000 and the remainder Calculate the quotient and remainder.

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, such as sensor values, the value multiplied by 100 may be passed as a uint16_t type, but since calculation processing on a microcontroller without a division circuit takes a reasonable amount of time, the calculation is performed by approximate calculation and correction using addition, subtraction, multiplication and bit shift.

Pass val as the value to be calculated, rem as the variable to store the remainder, and neg as the variable to store the sign.

The return value is the quotient value (always positive), rem stores the remainder value (always positive), and neg is true if negative.

The constraints of the calculation algorithm (overflow) determine the range of possible values for div100() and div1000(). The div100() corresponds to values from -9999999 to 9999999, and the div1000() corresponds to values from -999999999 to 99999999.

Approximate formula to obtain the quotient

div100()
  int dv = val * 1311 >> 17;
  
div1000()
  int dv = val * 131 >> 17;

Usage examples

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

Approx. 10 times faster.

Output results

// Conversion Options
struct DIVFMT {
  static const int STD = 0; // displays with minimul 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 for storing 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;

// Implement an 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, which stores the result of division, has a format() method to obtain a _div_chars class object. The _div_chars() class object contains a string buffer and has methods to access the string buffer as const char* type. It also implements the << operator for Serial objects.

The first parameter dig_quo of the format() method specifies the number of output digits (not including the sign part). If the number of output digits is not sufficient (hereafter referred to as missing digits), it is filled with blanks or 0. The second parameter opt specifies the format.

opt parameter
content

DIVFMT::STD

Standard output, with missing digits filled in with spaces and - appended only for negative values.

DIVFMT::PAD_ZERO

Missing digits are filled with 0.

DIVFMT::SIGN_PLUS

A + sign is also added to positive values.

DIVFMT::PAD_ZERO_SIGN_PLUS

Missing digits are filled with 0 and a + sign is also added to positive values.

DIVFMT::SIGN_SPACE

For positive values, a space is added in place of the + sign.

DIVFMT::PAD_ZERO_SIGN_SPACE

Missing digits are filled with 0, and a space is added in place of the + sign for positive values.

Example

//// Direct output from div_result_i32 object
Serial << div100(-1234) << crlf;
// Result: -12.34 

//// Output in 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

Since division is a costly operation in the TWELITE wireless microcontroller, we added a division algorithm with a limited purpose.

In the library, some sensor values such as temperature and humidity are expressed using 100 times the value (2512 for 25.12°C), so we defined a simple procedure to obtain the quotient divided by 100 and the remainder.

As for dev_result_i32::format(), it is to avoid complications when formatting output.

最終更新