Получить количество цифр в беззнаковое длинное целое число с#
Я пытаюсь определить количество цифр в номере c# ulong, я пытаюсь сделать это, используя некоторую математическую логику, а не используя ToString().Длина. Я не сравнивал подходы 2, но видел другие сообщения об использовании системы.Математика.напольная система.Математика.Log10 (number)) + 1 для определения количества цифр. Кажется, работает нормально, пока я не перейду от 99999999999999997 к 999999999999998, и в этот момент я начинаю получать неправильный счет.
кто-нибудь сталкивался с этим проблема раньше ?
Я видел похожие сообщения с акцентом Java @ почему log (1000) / log(10) не совпадает с log10(1000)?, а также пост @ как получить отдельные цифры числа int? что указывает, как я мог бы достичь того же с помощью оператора%, но с гораздо большим количеством кода
вот код, который я использовал для имитации этого
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);
спасибо заранее
Пэт
4 ответов
log10 будет включать преобразование с плавающей запятой-следовательно, ошибка округления. Ошибка довольно мала для double, но это большое дело для точного целого числа!
за исключением .Метод ToString() и метод с плавающей запятой, тогда да, я думаю, вам придется использовать итерационный метод, но я бы использовал целочисленное деление, а не по модулю.
целое деление на 10. Это результат>0? Если это так, повторите. Если нет, остановись. Число цифр - это число требуемых итераций.
например. 5 -> 0; 1 итерация = 1 цифра.
1234 -> 123 -> 12 -> 1 -> 0; 4 итераций = 4 цифры.
Я хотел бы использовать ToString().Length
Если вы не знаете, это будет называться миллионы раз.
"преждевременная оптимизация-корень всех зол" - Donald Knuth
С документация:
по умолчанию двойное значение содержит 15 десятичные цифры точности, хотя максимум 17 цифр внутренне.
Я подозреваю, что вы работаете в пределы точности. Ваше значение 999,999,999,999,999,998, вероятно, находится на пределе точности. И с тех пор ulong
должен быть преобразован в double
перед вызовом Math.Log10
, вы видите эту ошибку.
другие ответы выложили почему это произойдет.
вот пример довольно быстрого способа определения "длины" целого числа (некоторые случаи исключены). Это само по себе не очень интересен, но я включаю его здесь, потому что используя этот метод в сочетании с 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, разбитая на" группы", вероятно, еще быстрее, но это слишком много повторяющихся типов на мой вкус.)
удачи в кодировании.