# div100()

１０、１００または１０００で割った商と余りを計算します。

```cpp
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);

```

センサー値などで100倍した値を`uint16_t`型にして受け渡しする場合がありますが、除算回路がないマイコンでの計算処理には相応の時間がかかるため、加算・減算・乗算とビットシフトを用いた近似計算と補正により計算を行います。

`val`に計算したい値、`rem`は余りの格納変数、`neg`は符号を格納する変数を渡します。

戻り値は商の値（常に正）、`rem`には余りの値（常に正）、`neg`は負なら`true`が格納されます。

計算アルゴリズムの制約（桁あふれ）から`div100()`と`div1000()`での計算可能な値域が決まっています。`div100()`は-99999～99999までの値に対応し、`div1000()`は-999999～999999までの値に対応します。

{% hint style="info" %}
商を得る近似計算式

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

{% endhint %}

### 使用例

```cpp
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);
```

### 計算速度

１０倍程度になります。

## 結果の出力

```cpp
// 変換オプション
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 _div_chars {
  ...
  const char* begin() const {...}
  const char* end() const {...}
  const char* c_str() const { return begin(); }
  operator const char*() const { return begin(); }
};

// format()メソッド
_div_chars div_result_i32::format(
    int dig_quo = 0, uint32_t opt = DIVFMT::STD) const;

// 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&);
};
```

割り算の結果を格納する`div_result_i32`クラスには`format()`メソッドを用い`_div_chars`クラスオブジェクトを得ることが出来る。`_div_chars()`クラスオブジェクトは文字列バッファを内包していて`const char*`型として文字列バッファにアクセスするメソッドが用意されている。また、`Serial`オブジェクトに対する`<<`演算子も実装している。

`format()`メソッドのパラメータの１番目`dig_quo`は出力桁数（符号部を含まず）を指定します。出力桁数に足りない場合（以下、不足桁）は空白または`0`で埋めます。２番目のパラメータ`opt`は書式を指定します。

| optパラメータ                      | 内容                                    |
| ----------------------------- | ------------------------------------- |
| `DIVFMT::STD`                 | 標準的な出力で、不足桁は空白で埋め、負の値に限り`-`を付加します。    |
| `DIVFMT::PAD_ZERO`            | 不足桁は`0`で埋めます。                         |
| `DIVFMT::SIGN_PLUS`           | 正の値にも`+`符号を付加します。                     |
| `DIVFMT::PAD_ZERO_SIGN_PLUS`  | 不足桁は`0`で埋め、正の値にも`+`符号を付加します。          |
| `DIVFMT::SIGN_SPACE`          | 正の値の場合は`+`符号の替わりに空白を付加します。            |
| `DIVFMT::PAD_ZERO_SIGN_SPACE` | 不足桁は`0`で埋め、正の値の場合は`+`符号の替わりに空白を付加します。 |

### 例

```cpp
//// div_result_i32オブジェクトから直接出力
Serial << div100(-1234) << crlf;
// 結果: -12.34 

//// 3桁で出力します
Serial << div100(3456).format(3, DIVFMT::PAD_ZERO_SIGN_PLUE) << crlf;
// 結果: +034.56 

//// c_str()を使ってconst char*を得る
char str1[128];
auto x = div100(-5678);
mwx_snprintf(str1, 16, "VAL=%s", x.format.c_str()); // const char*
Serial << str1;
// 結果: VAL=-56.78
```

## 背景

TWELITE 無線マイコンでは除算はコストが高い演算であるため、目的を限定した除算アルゴリズムを追加した。

ライブラリ内では温度・湿度といった一部のセンサー値、100倍の値（25.12℃なら2512)を用いて表現しているため、100で割った商と余りを得るための簡素な手続きを定義した。

`dev_result_i32::format()`については、書式出力を行う際の煩雑さを避けるためである。
