【Unity】四捨五入を考える

座標をポジション管理する時に
前後の座標の中間点をどう処理するか悩みませんか?

ケロは、いつも悩んでおります。(-_-)ゞ゛ウーム

例えば、ピッチが20でポジションの座標が0、20、40…
とあった場合、オブジェクトが30の位置に停止したら
20なのか40なのか…

ポジションの計算は、座標/ピッチで出せるのですが、
30/20=1.5になります。

こう言う時に四捨五入を使えると、ポジショニングに
法則性を持たせる事ができるかなと思います。

そこで、四捨五入を調べてみたのですが、
余り使われる事がないのか見つける事が出来ませんでした。

それなら作ってしまえと言う、あまり内容の無い記事となります(;^_^A


まず便利なMathf関数をおさらいしてみます。

・Mathf.CeilToInt(数値) 小数点以下切り上げ
・Mathf.FloorToInt(数値) 小数点以下切り捨て
・Mathf.RoundToInt(数値)小数点以下偶数丸め

実際にどうなるのか検証したいので、

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoundTest : MonoBehaviour
{

public float[] num;

public void Processing()
{
Debug.Log(Mathf.〇〇(num[0]));
Debug.Log(Mathf.〇〇(num[1]));
Debug.Log(Mathf.〇〇(num[2]));
}
}

こんなコードを作って、public変数に数値を代入して
Processing()メソッドをボタンから呼び出してみる事にします。

コンポーネントは
Mathf①.jpg
要素数を3にして数値を設定します。


Mathf.CeilToInt
小数点以下を切り上げます。

public void Processing()
{
Debug.Log(Mathf.CeilToInt(num[0]));
Debug.Log(Mathf.CeilToInt(num[1]));
Debug.Log(Mathf.CeilToInt(num[2]));
}



処理結果は
Mathf②.jpg
切り上がるので、全て1になります。


Mathf.FloorToInt
小数点以下を切り捨てます。

public void Processing()
{
Debug.Log(Mathf.FloorToInt(num[0]));
Debug.Log(Mathf.FloorToInt(num[1]));
Debug.Log(Mathf.FloorToInt(num[2]));
}



処理結果は、
Mathf③.jpg
切り捨てるので、全て0になります。


Mathf.RoundToInt
小数点以下を偶数丸めします。


public void Processing()
{
Debug.Log(Mathf.RoundToInt(num[0]));
Debug.Log(Mathf.RoundToInt(num[1]));
Debug.Log(Mathf.RoundToInt(num[2]));
}

この関数は一番、四捨五入に近い動きをしますが、
一桁目が奇数か偶数で違った動きをします。

public変数をそのまま処理してみます。
Mathf④.jpg
四捨五入なら0.5は1にならないといけないのですが、
0になっています。

少し分かりにくいので、変数を変えて処理してみます。
Mathf⑤.jpg
Mathf⑥.jpg
変な感じになりますね。

偶数丸めと言う言葉も初めて知ったのですが、
この関数を使うと四捨五入のように処理されるのですが、
一桁目が偶数になるように処理が行われます。

0.5なら偶数である0になり、
1.5なら偶数である2になります。

0.51にすると1になると言う、なんとも言えない処理です。
かなり使い方に注意が必要になります。


純粋に四捨五入する事ができないので、
ポジショニングには使いにくいかと思います。

では、四捨五入の処理を考えてみたいと思います。
・入力数値の小数点以下一位を判断する
・判断した数値が0~4なら切り捨て
・判断した数値が5~9なら切り上げ

こんな感じで処理ができそうです。

入力した数値から小数点以下一位の数値を取り出す方法を考えてみます。

public float num;

public void Rounding()
{
float dec = num - Mathf.FloorToInt(num);
int intege = Mathf.FloorToInt(dec * 10);
}

入力したnumから整数化したnumを減算すれば、
小数点以下が取り出せます。

取り出した数値を10倍すれば小数点以下一位を一桁上げれるので、
残りの少数を切り離して整数化すれば、判別できそうです。

if (intege >= 5)
{
Debug.Log(Mathf.CeilToInt(num));
}
else
{
Debug.Log(Mathf.FloorToInt(num));
}

判別は、5以上なら切り上げ
4以下なら切り捨てればOKかと。

このコードで試してみます。
Mathf⑦.jpg
Mathf⑧.jpg
うまくいきました。ヽ(´▽`)/~♪

座標取得のメソッドに、この演算を入れると分かりにくくなる場合は、

public float num;
private int Pos;

void Start()
{
Pos = Rounding();
}

int Rounding()
{
float dec = num - Mathf.FloorToInt(num);
int intege = Mathf.FloorToInt(dec * 10);

if (intege >= 5)
{
return Mathf.CeilToInt(num);
}
else
{
return Mathf.FloorToInt(num);
}
}

関数として呼び出すと見やすくなるかと思います。

あまり需要はないかも知れませんが(゜ρ゜)アウゥ
四捨五入は以上となります。


追記
小数点以下丸めは、JIS規格により定義されているようです。
小数点以下偶数丸めも規格にあって、
長さを累積する際、四捨五入だと誤差が大きくなるそうです。
誤差を少なくする為に考えられたのが、偶数丸めだそうです。

意味があったんですね~
良い勉強になりました( ^ー゜)b

この記事へのコメント