C# 根据所需的小数位数*和*sig设置数字格式

C# 根据所需的小数位数*和*sig设置数字格式,c#,C#,我们的科学应用程序允许用户配置显示数值时使用的有效数字和小数位数。当前正在使用以下代码进行格式化:- var sigFigFormatted = valueToConvert.ToString("G" + numberOfSigFigs); var theFullyFormattedValue = Convert.ToDouble(sigFigFormatted) .ToString("F" + numberOfDecimalPl

我们的科学应用程序允许用户配置显示数值时使用的有效数字和小数位数。当前正在使用以下代码进行格式化:-

var sigFigFormatted = valueToConvert.ToString("G" + numberOfSigFigs);
var theFullyFormattedValue = Convert.ToDouble(sigFigFormatted)
                                 .ToString("F" + numberOfDecimalPlaces);

我不喜欢所有这些从字符串到字符串的转换,并且忍不住想一定有一个更有效的解决方案?

看看公认的答案

我已将已接受答案中的代码移植到C#,并进行了一些测试。 代码:


因此
NumericExtensions.RoundToSignificantFigures
显示了更有效的数字格式方法。

从什么角度看“有效”?@zerkms我们的应用程序在UI中显示了100000个数值,多次调用上述代码在性能分析器中显示为一个小瓶颈。我猜对ToString()和Convert()的调用会影响性能,所以我想知道是否有一种“更灵活”的方法可以做到这一点,例如使用自定义格式字符串。但您并没有同时显示所有这些,对吗?我真的不明白为什么你需要同时显示100000个数字,或者它如何在屏幕上显示。你不能修复UI,让它不会同时显示所有这些吗?否则,您必须显示更多的代码,以便我们可以看到更多您尝试执行的操作,从何处获取不同的值,以及如何显示数据。您可以始终将格式化的值与数字值并排存储。当然,它违反了规范化规则,但这是一个很好的例子,说明为了获得特定的性能增益而违反规则。只需确保保护应用程序的其余部分不受这种重复性的影响。@DanielMesSer数值结果显示在各种数据网格中。非常感谢您花时间回答这个问题-我今天将尝试一下。
using System;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication1
{
    public static class NumericExtensions
    {
        public static double RoundToSignificantFigures(this double num, int n)
        {
            if (num == 0)
            {
                return 0;
            }

            double magnitude = Math.Pow(10, n - (int)Math.Ceiling(Math.Log10(Math.Abs(num))));
            double shifted = Math.Round(num * magnitude);
            return shifted / magnitude;
        }

        public static double RoundToSignificantFiguresWithConvert(this double num, int n)
        {
            var sigFigFormatted = num.ToString("G" + n.ToString());
            return Convert.ToDouble(sigFigFormatted);
        }
    }

    class Program
    {
        static string[] Test1(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
        {
            var result = new string[numbers.Length];
            for (int i = 0; i < numbers.Length; i++)
            {
                result[i] = numbers[i].RoundToSignificantFigures(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
            }
            return result;
        }

        static string[] Test2(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
        {
            var result = new string[numbers.Length];
            for (int i = 0; i < numbers.Length; i++)
            {
                result[i] = numbers[i].RoundToSignificantFiguresWithConvert(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
            }
            return result;
        }

        static void Main(string[] args)
        {
            // create an array or random numbers 
            var rng = new Random();
            var numbers = new double[100000];
            for (int i = 0; i < numbers.Length; i++)
            {
                numbers[i] = 10000000000000000000D * (rng.NextDouble() - 0.5D);
            }

            const int numberOfSigFigs = 3;
            const int numberOfDecimalPlaces = 3;

            // make first run without time measurement
            Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
            Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);

            const int numberOfIterations = 100;
            var sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < numberOfIterations; i++)
            {
                Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
            }
            sw.Stop();
            Console.WriteLine("Test1 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());

            sw.Restart();
            for (int i = 0; i < numberOfIterations; i++)
            {
                Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);
            }
            sw.Stop();
            Console.WriteLine("Test2 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());

            Console.ReadKey();
        }

    }

}
Test1 elapsed 7259 ms
Test2 elapsed 12918 ms