Как получить размер числа в .net?

Я хочу, чтобы заданное двойное число возвращало его «размер» (известный как | число | или количество цифр без чисел после точки), например:

12.324654 -> 2
12 -> 2
0.99 -> 0
1.01 -> 1
901 -> 3
-0.99 -> 0
-9.999 -> 1

Должна быть функция .net, с которой я не знаком, которая делает это.

Спасибо.


person Nir    schedule 28.07.2011    source источник
comment
Обычно |число| обозначает абсолютное значение - очевидно, это не то, что вам нужно.   -  person Mathias    schedule 29.07.2011
comment
целая часть числа находится слева от десятичной точки. Дробная часть находится справа. Итак, вы ищете способ измерить количество знаков после запятой, используемых целой частью.   -  person Kirk Woll    schedule 29.07.2011
comment
|число| также известный как размер группы/числа. Это связано с тем, что вы ходите ..   -  person Nir    schedule 29.07.2011


Ответы (6)


((int)Math.Abs(12.324654)).ToString().Length

Math.Abs будет преобразовано в положительное число (не нужно считать отрицательный знак)
(int) удалит цифры после десятичной точки
ToString() преобразует в строку ===> "12"
Length говорит вам, сколько символов есть
есть пограничный случай, когда (int)( some number ) == 0, где длина даст вам 1-- вы можете этого не хотеть, поэтому имейте в виду возможность

теперь, что вы МОЖЕТЕ сделать, это сделать это методом расширения....

public static class Utils
{
   public static int Size(this double n)
   {
     int i = (int)Math.Abs(n);
     if ( i == 0 ) return 0;
     return  i.ToString().Length;
   }
}

12.324654.Size() == 2;
person Muad'Dib    schedule 28.07.2011
comment
Довольно прямолинейно :) +1 Мне нравится простота. - person Patrick Desjardins; 29.07.2011
comment
Не учитывает отрицательные числа. Вам понадобится абсолютное значение, иначе требование исходного вопроса (-9,999 -> 1) не сработает. Возможно ((int)(Math.Abs(12.324654)).ToString().Length; ? В остальном мне нравится простота этого подхода. - person ZombieSheep; 29.07.2011
comment
:) Сейчас обновился, удалю свой ответ. :) Я думаю, что необходимо учитывать возможность того, что результат будет равен 0, поскольку OP хотел, чтобы 0 возвращал нулевую длину... - person ZombieSheep; 29.07.2011
comment
0.99 -> 0 также вернет 1, не так ли? - person hungryMind; 29.07.2011
comment
@hungryMind, (int)(someDouble) отбрасывает часть после запятой, поэтому (int)0.99 == 1 (из-за 0) --- изменил код, чтобы исправить это - person Muad'Dib; 29.07.2011
comment
Вот что я говорю, 0,99 ожидает 0 в качестве результата, но ваша формула вернет 1. Это будет работать нормально, ((int)Math.Abs(yourNumber *10)).ToString().Length - 1 - person hungryMind; 29.07.2011
comment
@hungryMind, ты прав. Я добавил комментарии о пограничном случае. Спасибо! - person Muad'Dib; 29.07.2011
comment
@muad как насчет моего решения? Разве это не прямолинейно - person hungryMind; 29.07.2011

Trylog10(max(abs(число), 0,5)) + 1 округлено в меньшую сторону.

Или, в реальном синтаксисе C#:

(int)(Math.Log10(Math.Max(Math.Abs(number), 0.5)) + 1)

Хорошо, как это работает?

Во-первых, p = log10(x) — это основание 10 логарифм от x; то есть такое значение, что 10, возведенное в p-ю степень (или 1, за которой следуют p нули), равно x. Логарифм, по сути, измеряет длину числа, за исключением того, что это гладкая функция x:

График логарифма x по основанию 10

(Обратите внимание, что в языках, которые не предоставляют функцию логарифмирования по основанию 10, мы всегда можем вычислить ее как log10(x) = log(x< /em>) / log(10), где log() — функция логарифмирования по любому основанию.)

Например, у нас есть

log10(1) = 0,0
log10(10) = 1,0
log10(100) = 2,0
log10(1000) = 3,0

но также, например:

log10(5) = 0,69897
log10(50) = 1,69897
log10(500) = 2,69897
log10(5000) = 3,69897

Как правило,n ≤ log10(x) ‹ n+1whenever10n< /em>x ‹ 10n+1.

Глядя на приведенные выше значения, должно быть достаточно легко увидеть, что, чтобы получить количество цифр по основанию 10 в целом числе, мы должны округлить его логарифм по основанию 10 до ближайшего целого числа и добавить 1 (потому что мы хотим длина 10 должна быть 2, а не 1).

Тем не менее, есть еще несколько крайних случаев, которые следует учитывать:

Во-первых, первоначальный вопросник хотел, чтобы длина x равнялась длине x. Логарифм определяется только для положительных чисел, поэтому мы заменяем x его абсолютным значением, чтобы оно всегда было положительным.

Во-вторых, первоначальный вопросник также хотел, чтобы длина чисел от 0 до 1 была равна нулю. Однако логарифм может принимать сколь угодно большие отрицательные значения:

log10(0,1) = 1,0
log10(0,01) = 2,0
log10(0,001) = 3,0
log10(0,0001) = 4,0

и действительно, log10(0) = . Чтобы удовлетворить этому требованию, мы просто удостоверимся, что число, длина которого мы вычисляем, никогда не может опускаться ниже 0,5, используя его максимум и 0,5 в качестве входных данных для журнал10(). (Мы могли бы использовать любое число от 0,1 до 1 в качестве порога, но 0,5 — это хорошая круглая двоичная дробь.)

Кроме того, мы должны добавить +1 к логарифму перед его округлением, чтобы округляемое число всегда было неотрицательным. Это связано с тем, что (int) в C# фактически округляет отрицательные числа в большую сторону до нуля. Например, поскольку log10(0,5) 0,3, выражение (int)Math.Log10(0.5) + 1 (округление перед сложением) будет оцениваться как 0+1 = 1, а не как ожидаемый 0.

person Ilmari Karonen    schedule 28.07.2011
comment
Как вы можете записать отрицательное число? - person Patrick Desjardins; 29.07.2011
comment
@Daok: Ты не можешь, извини. Исправлено. - person Ilmari Karonen; 29.07.2011
comment
Можете ли вы объяснить это мне? Я не понимаю логики, но нашел это очень мудрым +1 - person Patrick Desjardins; 29.07.2011
comment
@Ilmari: Как насчет ввода 0? И я не знаю С#, но заставит ли функция min() возвращать 0? - person zw324; 29.07.2011
comment
Хорошо, я добавил объяснение, а также исправил min() на max(). (Спасибо, @Ziyao Wei!) - person Ilmari Karonen; 29.07.2011
comment
Спасибо за ответ и объяснение!! Я не буду использовать это, потому что знаю, что со временем, когда мне нужно будет поддерживать код, эта строка не будет иметь для меня никакого смысла. Кроме того, мои числа не такие уж большие, поэтому в настоящее время функция журнала не нужна. - person Nir; 29.07.2011
comment
Ну, вы всегда можете обернуть его в метод и задокументировать, что он делает. (Ps. Я немного подправил ответ: я не знаю, нравится ли C # Math.Log10() 0 в качестве аргумента или нет, но при перемещении Max() внутри него эта проблема никогда не возникает.) - person Ilmari Karonen; 29.07.2011
comment
Ваш ответ стоит меньше/больше, чем ответ @Muad'Dib? - person Nir; 29.07.2011
comment
@nir: Трудно сказать, не проведя тест. Я надеюсь, что мой будет быстрее, по крайней мере, для больших чисел, но в конечном итоге это может привести к произвольным различиям в накладных расходах реализации. В любом случае, оба должны быть достаточно быстрыми практически для любых практических целей. - person Ilmari Karonen; 29.07.2011
comment
@nir (продолжение): я на самом деле не программист на C#, но я провел быстрый тест эквивалентных решений в Perl просто потому, что мог: на этом языке решение для подсчета символов быстрее для чисел ниже 2^32, но значительно замедляется выше этой точки (в то время как решение журнала продолжает работать примерно с той же скоростью). Как я уже отметил, это, вероятно, связано с деталями реализации, поэтому другие языки и платформы, вероятно, будут отличаться. - person Ilmari Karonen; 29.07.2011
comment
Привет, @DavideCannizzo. Просто из любопытства, есть ли особая причина, по которой вы добавили пробелы вокруг (некоторых) математических выражений выше? Я не уверен, что они действительно улучшают читаемость (особенно для одиночных переменных или в выражениях, таких как p-я степень), но я решил спросить, прежде чем просто отменить ваше редактирование, на всякий случай что-то мне здесь не хватает. - person Ilmari Karonen; 05.01.2018
comment
У выражений есть некоторое внутреннее пространство (например, между операторами), поэтому я считаю, что они более аккуратны с довольно большим пространством в начале и в конце. - person Davide Cannizzo; 05.01.2018

Вы можете сделать что-то вроде ниже, чтобы учесть ваши 0 цифры, возвращающие нулевую длину

private static int CountAbsoluteDigits(double p) {
    int absolute = (int)Math.Abs(p);
    if (0 == absolute)
        return 0;
    else
        return absolute.ToString().Length;
}

...

var length = CountAbsoluteDigits(12.324654);

Это результат, который я получил с номерами, которые вы предоставили.

12.324654 -> 2
12 -> 2
0.99 -> 0
1.01 -> 1
901 -> 3
-0.99 -> 0
-9.999 -> 1

person Quintin Robinson    schedule 28.07.2011

Кража формата Квинтина:

private static int CountAbsoluteDigits(double p) {
    int ip = (int)p;
    int answer = 0;
    while (ip!=0) {
        answer++;
        ip/=10;
    }
    return answer;
}

Никаких трюков (например, abs(), if) здесь не требуется.

person zw324    schedule 28.07.2011

Кортси Муад'Диб

int GetLength(double value){
    return ((int)Math.Abs(value*10d)).ToString().Length - 1
}
person hungryMind    schedule 28.07.2011

Преобразование в целое число и преобразование результата в строку будет работать только в том случае, если значение находится в пределах диапазона целого числа. Если вам нужны значения выше 2 миллиардов, вам нужно либо работать с журналами, либо конвертировать двойное число в строку.

static int GetLength(double d)
{
    d = Math.Abs(d);
    if (d < 1.0) return 0;
    if (double.IsInfinity(d)) return int.MaxValue;
    if (double.IsNaN(d)) return 0;
    return (int)Math.Floor(Math.Log10(d)) + 1;
}

static int GetLength2(double d)
{
    d = Math.Abs(d);
    if (d < 1.0) return 0;
    if (double.IsInfinity(d)) return int.MaxValue;
    if (double.IsNaN(d)) return 0;
    string s = d.ToString("E"); // returns a string in the format "1.012435E+001"
    return int.Parse(s.Substring(s.Length - 3)) + 1;
}

static void Test(double d) { Debug.WriteLine(d + " -> " + GetLength(d) + ", " + GetLength2(d)); }

static void Main(string[] args)
{
    Test(0);
    Test(0.125);
    Test(0.25);
    Test(0.5);
    Test(1);
    Test(2);
    Test(10);
    Test(10.5);
    Test(10.25);
    Test(10.1243542354235623542345234523452354);
    Test(999999);
    Test(1000000);
    Test(1000001);
    Test(999999.111);
    Test(1000000.111);
    Test(1000001.111);
    Test(double.MaxValue);
    Test(double.MinValue);
    Test(double.PositiveInfinity);
    Test(double.NegativeInfinity);
    Test(double.NaN);
    Test(double.Epsilon);
}

Полученные результаты:

0 -> 0, 0
0.125 -> 0, 0
0.25 -> 0, 0
0.5 -> 0, 0
1 -> 1, 1
2 -> 1, 1
10 -> 2, 2
10.5 -> 2, 2
10.25 -> 2, 2
10.1243542354236 -> 2, 2
999999 -> 6, 6
1000000 -> 7, 7
1000001 -> 7, 7
999999.111 -> 6, 6
1000000.111 -> 7, 7
1000001.111 -> 7, 7
1.79769313486232E+308 -> 309, 309
-1.79769313486232E+308 -> 309, 309
Infinity -> 2147483647, 2147483647
-Infinity -> 2147483647, 2147483647
NaN -> 0, 0
4.94065645841247E-324 -> 0, 0
person David Yaw    schedule 28.07.2011