C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

有効数字で切り上げるには?

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■87947 / inTopicNo.1)  有効数字で切り上げるには?
  
□投稿者/ なっとう (6回)-(2018/07/18(Wed) 15:00:41)

分類:[C#] 

2018/07/18(Wed) 16:51:26 編集(投稿者)
2018/07/18(Wed) 16:49:12 編集(投稿者)

下記の数値(左側)を次(右側)のように有効数字2桁で切り上げたいと考えております。

入力されるnは10<n<1,000,000の実数です。
123456 130000
135483 140000
38574354 39000000
378321 380000
2489 2500
33458 34000

Mathの中に様々な処理を行うメソッドがありますが、目的と一致するものが見当たらないので自力で作ってみましたが、結構長くなってしまいました。もっと簡潔な書き方は無いのでしょうか・・・。

long n = 38574354;
int digit = ((int)Math.Log10(n) + 1);
n = (long)(Math.Ceiling(n / Math.Pow(10, digit - 2)) * (Math.Pow(10, digit - 2)));

以上、よろしくお願いいたします。

引用返信 編集キー/
■87948 / inTopicNo.2)  Re[1]: 有効数字で切り上げるには?
□投稿者/ furu (173回)-(2018/07/18(Wed) 16:13:07)
No87947 (なっとう さん) に返信

VB.NET?

C#なら、^は、排他的論理和です。

それと、実数と書かれているので
  99.000000000001 → 100
でしょうか?
引用返信 編集キー/
■87949 / inTopicNo.3)  Re[2]: 有効数字で切り上げるには?
□投稿者/ なっとう (7回)-(2018/07/18(Wed) 16:50:43)
No87948 (furu さん) に返信
失礼しました。上記サンプルコードの方は修正しました。

> それと、実数と書かれているので
>   99.000000000001 → 100
> でしょうか?
仰る通りです。
引用返信 編集キー/
■87950 / inTopicNo.4)  Re[1]: 有効数字で切り上げるには?
□投稿者/ サメ (1回)-(2018/07/18(Wed) 20:22:21)
No87947 (なっとう さん) に返信

実質2行なので十分簡潔だと思いますよ。
処理はExcelのMROUNDみたいな感じですね。
MROUNDは指定した倍数で丸めるものですが
それの切り上げバージョン。

MROUNDを模倣するならこうなりますけど
長くなるだけですね。

static void Main(string[] args)
{
    double n = 99.000000000001;
    int digit = ((int)Math.Log10(n) + 1);
    System.Diagnostics.Debug.WriteLine(MCeiling(n, Math.Pow(10, digit - 2)));
}

static double MCeiling(double number, double multiple)
{
    return Math.Ceiling(number / multiple) * multiple;
}

引用返信 編集キー/
■87951 / inTopicNo.5)  Re[2]: 有効数字で切り上げるには?
□投稿者/ furu (174回)-(2018/07/18(Wed) 20:53:24)
No87950 (サメ さん) に返信
整数(long)だけだとして
なっとうさんのやりかたを見ていなかったら
(Ceiling,Log10,Powなんて思いつかない)

var a = long.Parse("1" + new string('0', n.ToString().Length - 2));
n = (n + a - 1) / a * a;

かな。

簡潔ではないね。
引用返信 編集キー/
■87952 / inTopicNo.6)  Re[3]: 有効数字で切り上げるには?
□投稿者/ なっとう (8回)-(2018/07/19(Thu) 10:57:52)
No87950 (サメ さん) に返信
No87951 (furu さん) に返信
回答ありがとうございます。

一発で変換する関数が実はあるのではないかと思ったのですが、やっぱり無いのでしょうかね。
エクセルだと切り上げしたい桁数を整数方向はマイナス値で指定出来るので、C#も出来るんじゃないかとちょっと期待してましたがちょっと残念です。
「=ROUNDUP(A1,-INT(LOG10(A1))+1)」

取り敢えず自作のものを拡張メソッド化するなりして対応しようかと思います。

ありがとうございました。

解決済み
引用返信 編集キー/
■87953 / inTopicNo.7)  Re[1]: 有効数字で切り上げるには?
□投稿者/ 魔界の仮面弁士 (1742回)-(2018/07/19(Thu) 11:01:33)
2018/07/19(Thu) 11:02:59 編集(投稿者)
No87949 (なっとう さん) に返信
>> 99.000000000001 → 100
> 仰る通りです。

出力時の有効桁数が 2 桁だとして、
入力値 n のデータ型は何が利用されるのでしょうか?

float   型だと、精度が 23+1 bit なので、10進数での最大有効桁数は約 7.22472 桁。
double  型だと、精度が 52+1 bit なので、10進数での最大有効桁数は約 15.9546 桁。
decimal 型だと、精度が   96 bit なので、10進数での最大有効桁数は約 28.8989 桁。


今回の要件だと、出力時の値が Int32 で表される範囲なので、
どれを選んでも十分に思えるかもしれませんが、それでも
入力値の有効桁数というのは重要かと思います。
(入力値の有効桁数が 28 桁以下なら、Decimal を利用するのがお奨め)


たとえば、例示された「99.000000000001」の場合、有効桁数が 14 桁なので、
float(Single)だと精度不足に陥ります。具体的には、小数部が近似値に丸められるので、
float  で表すと 0b0_10000101_10001100000000000000000
double で表すと 0b0_10000000101_1000110000000000000000000000000000000000000001000110
に相当する内部表現バイナリで保持されます。("0b" は C#7.0 で導入された 2進数リテラル表記法)

そして上記の 2 進小数を 10 進数に変換してみると
前者は整数 99 を表していることになりますので、100 への切り上げを行えなくなります。
後者は小数 99.000000000000994759830064140260219573974609375 相当なので大丈夫なのですが。

var f = 99.000000000001F;  // float f = 99; と同義。
var d = 99.000000000001D;  // double d = 99.000000000001; と同義。
var m = 99.000000000001M;  // decimal m = 99.000000000001M; と同義。

解決済み
引用返信 編集キー/
■87954 / inTopicNo.8)  Re[2]: 有効数字で切り上げるには?
□投稿者/ なっとう (9回)-(2018/07/19(Thu) 11:59:07)
No87953 (魔界の仮面弁士 さん) に返信
今回は小数点以下は数桁しか使用しないので、そこまで深くは考えていませんでした。

詳しくありがとうございます。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ