Получить количество цифр в длинном целом без знака c # - PullRequest
11 голосов
/ 09 февраля 2011

Я пытаюсь определить количество цифр в числе c # ulong, я пытаюсь сделать это, используя некоторую математическую логику, а не ToString (). Length. Я не сравнивал 2 подхода, но видел другие посты об использовании System.Math.Floor (System.Math.Log10 (number)) + 1 для определения количества цифр. Кажется, работает нормально, пока я не перейду с 999999999999997 на 999999999999998, и в этот момент я получаю неправильный счет.

Кто-нибудь сталкивался с этой проблемой раньше?

Я видел похожие посты с выделением Java @ Почему log (1000) / log (10) не совпадает с log10 (1000)? , а также пост @ Как получить отдельные цифры целого числа? , который указывает, как я мог бы добиться того же, используя оператор%, но с гораздо большим кодом

Вот код, который я использовал для симуляции этого

Action<ulong> displayInfo = number => 
 Console.WriteLine("{0,-20} {1,-20} {2,-20} {3,-20} {4,-20}", 
  number, 
  number.ToString().Length, 
  System.Math.Log10(number), 
  System.Math.Floor(System.Math.Log10(number)),
  System.Math.Floor(System.Math.Log10(number)) + 1);

Array.ForEach(new ulong[] {
 9U,
 99U,
 999U,
 9999U,
 99999U,
 999999U,
 9999999U,
 99999999U,
 999999999U,
 9999999999U,
 99999999999U,
 999999999999U,
 9999999999999U,
 99999999999999U,
 999999999999999U,
 9999999999999999U,
 99999999999999999U,
 999999999999999999U,
 9999999999999999999U}, displayInfo);

Array.ForEach(new ulong[] {
 1U,
 19U,
 199U,
 1999U,
 19999U,
 199999U,
 1999999U,
 19999999U,
 199999999U,
 1999999999U,
 19999999999U,
 199999999999U,
 1999999999999U,
 19999999999999U,
 199999999999999U,
 1999999999999999U,
 19999999999999999U,
 199999999999999999U,
 1999999999999999999U
}, displayInfo);

Заранее спасибо

Pat

Ответы [ 4 ]

7 голосов
/ 09 февраля 2011

log10 будет включать преобразование с плавающей запятой - отсюда ошибка округления.Ошибка довольно мала для двойного числа, но имеет большое значение для точного целого числа!

За исключением метода .ToString () и метода с плавающей запятой, тогда да, я думаю, вам придется использоватьитерационный метод, но я бы использовал целочисленное деление, а не по модулю.

целочисленное деление на 10. Является ли результат> 0?Если так итерируйте.Если нет, остановись.Количество цифр - это количество требуемых итераций.

Например.5 -> 0;1 итерация = 1 цифра.

1234 -> 123 -> 12 -> 1 -> 0;4 итерации = 4 цифры.

6 голосов
/ 09 февраля 2011

Я бы использовал ToString().Length, если вы не знаете, что это будет вызываться миллионы раз.

«преждевременная оптимизация - корень всего зла» - Дональд Кнут

3 голосов
/ 09 февраля 2011

Из документации :

По умолчанию значение Double содержит 15 десятичных знаков точности, хотя внутренне поддерживается максимум 17 знаков.

Я подозреваю, что вы работаете в пределах точности.Ваше значение 999,999,999,999,998, вероятно, находится на пределе точности.И поскольку ulong необходимо преобразовать в double перед вызовом Math.Log10, вы видите эту ошибку.

0 голосов
/ 09 февраля 2011

Другие ответы опубликовали почему это происходит.

Вот пример довольно быстрого способа определения «длины» целого числа (за исключением некоторых случаев). Само по себе это не очень интересно, но я включаю его здесь, потому что использование этого метода в сочетании с Log10 может обеспечить "идеальную" точность для всего диапазона длин без знака без необходимости повторного вызова журнала.

// the lookup would only be generated once
// and could be a hard-coded array literal
ulong[] lookup = Enumerable.Range(0, 20)
    .Select((n) => (ulong)Math.Pow(10, n)).ToArray();
ulong x = 999;
int i = 0;
for (; i < lookup.Length; i++) {
    if (lookup[i] > x) {
        break;
    }
}
// i is length of x "in a base-10 string"
// does not work with "0" or negative numbers

Этот подход с таблицей поиска может быть легко преобразован в любую базу. Этот метод должен быть быстрее, чем итерационный метод деления на базы , но профилирование оставлено читателю в качестве упражнения. (Прямая ветвь if-then, разбитая на «группы», вероятно, еще быстрее, но это слишком много повторяющейся типизации для моих вкусов.)

Удачного кодирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...