質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

3回答

630閲覧

KMGT変換で「999999」にすると1Mになってしまう

MissingPiece598

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2022/11/25 11:24

前提

数値をKMGTに変換する処理を作成しました。
ただ「999999」を変換すると1Mになってしまいます。

おそらく下記の部分が不具合の原因かと思いますが、修正方法がわかりません。

C#

1 //有効桁数3桁+指数表記で文字列化 2    //※ここが原因?  3 var s = d.ToString("0.00E000");

ご教授いただければ幸いです。

実現したいこと

「999999」を変換すると"999.9K"になるのが理想です。

該当のソースコード

C#

1 /// <summary> 2 /// 単位をつけた文字列に変換します。 3 /// 12 -> 12 4 /// 1234 -> 1.23k 5 /// 123456 -> 123k 6 /// 12345678 -> 12.3m 7 /// 8 /// 単位:k, m, b, t, A, B, C, ... Z, AA, AB, AC, ... 9 /// 10 /// </summary> 11 /// <param name="d"></param> 12 /// <returns></returns> 13 public static string ToReadableString(this double d) 14 { 15 //マイナスは扱う気無し 16 if (d <= 0) return "0"; 17 //表示上は整数として見せるので、suffix(kmbtABC等)がつかない場合は少数部を破棄 18 if (d <= 1000) return ((int) d).ToString(); 19 20 //有効桁数3桁+指数表記で文字列化 21    //※ここが原因?  22 var s = d.ToString("0.00E000"); 23 24 //有効数字 25 float f = float.Parse(s.Substring(0, 4)); 26 27 //10の指数 28 var e = int.Parse(s.Substring(5, 3)); 29 30 //中途半端な指数は数値に掛け合わせておく 31 for (var i = 0; i < e % 3; i++) 32 { 33 f *= 10; 34 } 35 36 return f.ToString("###.##") + LevelToSuffix(e / 3); 37 } 38 39 /// <summary> 40 /// 10^3ごとにつけるSuffixの一覧 41 /// </summary> 42 private static string[] _suffixes; 43 44 private static string LevelToSuffix(int level) 45 { 46 if (_suffixes == null) 47 { 48 const string AtoZ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 49 var list = new List<string>(); 50 list.Add(""); 51 list.Add("k"); 52 list.Add("m"); 53 list.Add("b"); 54 list.Add("t"); 55 for (var x = 0; x < AtoZ.Length; x++) 56 for (var y = 1; y < AtoZ.Length; y++) 57 { 58 var str = string.Format("{0}{1}", AtoZ[x], AtoZ[y]).Trim(); 59 list.Add(str); 60 } 61 62 _suffixes = list.Take(308).ToArray(); //doubleは指数308まで 63 } 64 65 return _suffixes[level]; 66 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

何らかの課題でしょうか。だとすれば設問に問題がありますね。
というのも、コードを見るに非常に大きい数まで扱いたいようですが、引数がdoubleである限り正確な値が扱えるのはわずか2^53≒9007兆までです。(この記法でいうなら9.007A)
正確でない値をどうするかで考えられるスタンスがいくつかあるので、どういう回答を求められているのか(どうせ上の方は正確でないのに999999が1Mになるのも許容しないのか)、引数がdoubleなのは変えられないのかあたりが分からないとどうにも答えようがありません。

まあ、(引数を文字列にしたいところだが無理なら)適当にやるならdouble最大の17桁で文字列化してから文字列処理をすれば、文字列化が正しく行われる前提で、doubleとして最大限正しい値は出ると思います。
文字列化に正しさを丸投げしているわけですが、(大昔は誤った出力が出ることもあったようだが)最近のまともな環境ならたぶん大丈夫でしょう。

投稿2022/11/26 10:26

ikadzuchi

総合スコア3047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

指数表記にこだわらなければ、いかようにでも作れると思いますが・・・

CSharp

1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5internal static class Program 6{ 7 static void Main(string[] args) { 8 print(999999d); 9 print(1000000d); 10 print(12d); 11 print(1234d); 12 print(123456d); 13 print(12345678d); 14 Console.ReadKey(); 15 } 16 17 static void print(double d) { 18 Console.WriteLine($"{d} => {d.ToReadableString()}"); 19 } 20 21 public static string ToReadableString(this double d) { 22 var sign = Math.Sign(d); 23 var value = Math.Abs(d); 24 int i; 25 for (i = 0; i < suffixes.Length - 1; i++) { 26 if (value < 1000) { 27 break; 28 } 29 value = Math.Truncate(value / 10) / 100; 30 } 31 var str = (value * 1000).ToString(); 32 if (str.Length > 3) { 33 str = str.Substring(0, 3) + new string('0', str.Length - 3); 34 } 35 value = double.Parse(str) / 1000; 36 return (sign * value).ToString() + suffixes[i]; 37 } 38 39 private static string[] _suffixes; 40 private static string[] suffixes { 41 get { 42 if (_suffixes == null) { 43 const string AtoZ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 44 var list = new List<string>(); 45 list.Add(""); 46 list.Add("k"); 47 list.Add("m"); 48 list.Add("b"); 49 list.Add("t"); 50 for (var x = 0; x < AtoZ.Length; x++) 51 for (var y = 1; y < AtoZ.Length; y++) { 52 var str = string.Format("{0}{1}", AtoZ[x], AtoZ[y]).Trim(); 53 list.Add(str); 54 } 55 _suffixes = list.Take(308).ToArray(); 56 } 57 return _suffixes; 58 } 59 } 60}

ところで、頭3桁のみ有効桁にするのであれば、999999 → 999k になるのでは?

投稿2022/11/26 04:16

編集2022/11/26 10:27
KOZ6.0

総合スコア2628

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

「999999」を変換すると"999.9K"になるのが理想です。

 一般的な丸め処理では、そうはなりません。

 通常、有効桁数を減らす場合、四捨五入など、誤差が小さくなるように変換します。
なので、999999 を "0.00E000" で文字列にする場合、まず、丸め処理で、1000000になるので、ご希望の結果にはなりません。
質問者さんの仕様を満たすためには、文字列にする前に、切り捨てによる丸め処理を行うことが必要です。

投稿2022/11/25 15:58

YT0014

総合スコア1708

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MissingPiece598

2022/11/25 16:57

下記のようにした見たのですが、うまくいきません。 「文字列にする前に、切り捨てによる丸め処理」とはどのようにしたらよいでしょうか。 お手数ですが、ご教授いただけないでしょうか。 //dが「999999」     string temp = d.ToString(); //有効桁数3桁 int significantDigit = int.Parse(temp.Substring(0, 3)); //指数表記で文字列化 var suffix = significantDigit.ToString("0.00E000");
YT0014

2022/11/26 08:17

順番が逆です。 文字列返還の前に切り捨てです。 桁数不明なので、割と面倒な処理をしないと切り捨てできません。 未チェックですが、以下にコード // 上から3桁目の桁数の取得 int digit = (int)Math.Log10(d) - 2; // 上から3桁目を示す10の乗数を計算 double base = Math.Pow(10.0, (double)digit); // 切り捨てで上位3桁のみにする double d2 = Math.Floor(d / base) * base;
MissingPiece598

2022/11/26 11:38

ご回答ありがとうございます。 999kになりました、変換すると"999.9K"にする方法自力で見つけたいと思います。 ご教示いただきありがとうございます。
YT0014

2022/11/27 03:48

探す前に、こちらで提示したコードを、詳細に理解されることをお勧めします。 (int)Math.Log10(d) は、何を求めているのか? なぜ、2を引いているのか? Math.Pow(10.0, (double)digit) は、何を求めているのか? Math.Floor(d / base) * base は、何を求めているのか? 以上の質問に答えられますか? 参考までに、各関数のヘルプを挙げておきます。 https://learn.microsoft.com/ja-jp/dotnet/api/system.math.log10?view=net-7.0 https://learn.microsoft.com/ja-jp/dotnet/api/system.math.pow?view=net-7.0 https://learn.microsoft.com/ja-jp/dotnet/api/system.math.floor?view=net-7.0
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問