Bagaimana saya bisa menghitung jumlah digit angka di C #? Misalnya, angka 887979789 terdiri dari 9 digit.
Bagaimana saya bisa menghitung jumlah digit angka di C #? Misalnya, angka 887979789 terdiri dari 9 digit.
Jawaban:
Tanpa mengonversi menjadi string, Anda dapat mencoba:
Math.Ceiling(Math.Log10(n));
Koreksi mengikuti komentar ysap:
Math.Floor(Math.Log10(n) + 1);
n
yaitu 0
hanya dapat kembali 1
:) Terlalu pegangan nilai-nilai negatif hanya mengganti n
dengan Math.Abs(n)
.
Coba ini:
myint.ToString().Length
Apakah itu bekerja ?
int
, jadi saya berasumsi itu bukan masalah.)
Salah satu dari metode ekstensi berikut akan melakukan pekerjaan itu. Semuanya menganggap tanda minus sebagai digit, dan berfungsi dengan benar untuk semua kemungkinan nilai input. Mereka juga bekerja untuk .NET Framework dan .NET Core. Namun ada perbedaan kinerja yang relevan (dibahas di bawah), tergantung pada pilihan Platform / Kerangka Anda.
Versi int32:
public static class Int32Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this int n)
{
if (n >= 0)
{
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
else
{
if (n > -10) return 2;
if (n > -100) return 3;
if (n > -1000) return 4;
if (n > -10000) return 5;
if (n > -100000) return 6;
if (n > -1000000) return 7;
if (n > -10000000) return 8;
if (n > -100000000) return 9;
if (n > -1000000000) return 10;
return 11;
}
}
// USING LOG10:
public static int Digits_Log10(this int n) =>
n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this int n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10) != 0) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this int n) =>
n.ToString().Length;
}
Versi Int64:
public static class Int64Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this long n)
{
if (n >= 0)
{
if (n < 10L) return 1;
if (n < 100L) return 2;
if (n < 1000L) return 3;
if (n < 10000L) return 4;
if (n < 100000L) return 5;
if (n < 1000000L) return 6;
if (n < 10000000L) return 7;
if (n < 100000000L) return 8;
if (n < 1000000000L) return 9;
if (n < 10000000000L) return 10;
if (n < 100000000000L) return 11;
if (n < 1000000000000L) return 12;
if (n < 10000000000000L) return 13;
if (n < 100000000000000L) return 14;
if (n < 1000000000000000L) return 15;
if (n < 10000000000000000L) return 16;
if (n < 100000000000000000L) return 17;
if (n < 1000000000000000000L) return 18;
return 19;
}
else
{
if (n > -10L) return 2;
if (n > -100L) return 3;
if (n > -1000L) return 4;
if (n > -10000L) return 5;
if (n > -100000L) return 6;
if (n > -1000000L) return 7;
if (n > -10000000L) return 8;
if (n > -100000000L) return 9;
if (n > -1000000000L) return 10;
if (n > -10000000000L) return 11;
if (n > -100000000000L) return 12;
if (n > -1000000000000L) return 13;
if (n > -10000000000000L) return 14;
if (n > -100000000000000L) return 15;
if (n > -1000000000000000L) return 16;
if (n > -10000000000000000L) return 17;
if (n > -100000000000000000L) return 18;
if (n > -1000000000000000000L) return 19;
return 20;
}
}
// USING LOG10:
public static int Digits_Log10(this long n) =>
n == 0L ? 1 : (n > 0L ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this long n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10L) != 0L) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this long n) =>
n.ToString().Length;
}
Jawaban ini mencakup tes yang dilakukan untuk keduanya Int32
dan Int64
jenis, menggunakan larik 100.000.000
sampel acak int
/long
angka . Dataset acak diproses sebelumnya menjadi larik sebelum menjalankan pengujian.
Tes konsistensi antara 4 metode yang berbeda juga dieksekusi, untuk MinValue
, kasus perbatasan negatif, -1
, 0
, 1
, kasus perbatasan yang positif, MaxValue
dan juga untuk dataset acak seluruh. Tidak ada uji konsistensi yang gagal untuk metode yang disediakan di atas, KECUALI untuk metode LOG10 (ini akan dibahas nanti).
Tes dilaksanakan pada .NET Framework 4.7.2
dan .NET Core 2.2
; untuk x86
dan x64
platform, pada mesin Prosesor Intel 64-bit, dengan Windows 10
, dan dengan VS2017 v.15.9.17
. 4 kasus berikut memiliki efek yang sama pada hasil kinerja:
.NET Framework (x86)
Platform = x86
Platform = AnyCPU
, Prefer 32-bit
dicentang dalam pengaturan proyek
.NET Framework (x64)
Platform = x64
Platform = AnyCPU
, Prefer 32-bit
tidak dicentang di setelan proyek
.NET Core (x86)
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\x86\Release\netcoreapp2.2\ConsoleApp.dll
.NET Core (x64)
"C:\Program Files\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
"C:\Program Files\dotnet\dotnet.exe" bin\x64\Release\netcoreapp2.2\ConsoleApp.dll
Uji kinerja di bawah ini menghasilkan distribusi nilai yang seragam di antara berbagai nilai yang dapat diasumsikan oleh integer. Ini berarti ada peluang yang jauh lebih tinggi untuk menguji nilai dengan jumlah digit yang besar. Dalam skenario kehidupan nyata, sebagian besar nilai mungkin kecil, jadi IF-CHAIN akan bekerja lebih baik. Selanjutnya, prosesor akan menyimpan dan mengoptimalkan keputusan IF-CHAIN sesuai dengan kumpulan data Anda.
Seperti yang ditunjukkan @AlanSingfield di bagian komentar, metode LOG10 harus diperbaiki dengan casting ke double
dalam Math.Abs()
untuk kasus ketika nilai input adalah int.MinValue
ataulong.MinValue
.
Mengenai tes kinerja awal yang saya terapkan sebelum mengedit pertanyaan ini (sudah diedit jutaan kali), ada kasus khusus yang ditunjukkan oleh @ GyörgyKőszeg , di mana metode IF-CHAIN bekerja lebih lambat daripada metode LOG10.
Ini masih terjadi, meskipun besarnya perbedaan menjadi jauh lebih rendah setelah perbaikan untuk masalah yang ditunjukkan oleh @AlanSingfield . Perbaikan ini (menambahkan cast ke double
) menyebabkan kesalahan komputasi ketika nilai inputnya tepat -999999999999999999
: metode LOG10 mengembalikan, 20
bukan 19
. Metode LOG10 juga harus memiliki if
pelindung untuk kasus ketika nilai input adalah nol.
Metode LOG10 cukup rumit untuk berfungsi untuk semua nilai, yang berarti Anda harus menghindarinya. Jika seseorang menemukan cara untuk membuatnya bekerja dengan benar untuk semua tes konsistensi di bawah ini, silakan kirim komentar!
Metode WHILE juga mendapat versi refactored terbaru yang lebih cepat, tetapi masih lambat Platform = x86
(saya tidak dapat menemukan alasan mengapa, sampai sekarang).
Metode STRING selalu lambat: metode ini dengan rakus mengalokasikan terlalu banyak memori untuk apa-apa. Menariknya, di .NET Core, alokasi string tampaknya jauh lebih cepat daripada di .NET Framework. Senang mendengarnya.
Metode IF-CHAIN harus mengungguli semua metode lain dalam 99,99% kasus; dan, menurut pendapat pribadi saya, adalah pilihan terbaik Anda (mempertimbangkan semua penyesuaian yang diperlukan untuk membuat metode LOG10 berfungsi dengan benar, dan kinerja buruk dari dua metode lainnya).
Akhirnya, hasilnya adalah:
Karena hasil ini bergantung pada perangkat keras, saya sarankan untuk tetap menjalankan tes kinerja di bawah ini di komputer Anda sendiri jika Anda benar-benar perlu 100% yakin dalam kasus khusus Anda.
Di bawah ini adalah kode untuk uji kinerja, dan juga uji konsistensi. Kode yang sama digunakan untuk .NET Framework dan .NET Core.
using System;
using System.Diagnostics;
namespace NumberOfDigits
{
// Performance Tests:
class Program
{
private static void Main(string[] args)
{
Console.WriteLine("\r\n.NET Core");
RunTests_Int32();
RunTests_Int64();
}
// Int32 Performance Tests:
private static void RunTests_Int32()
{
Console.WriteLine("\r\nInt32");
const int size = 100000000;
int[] samples = new int[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = random.Next(int.MinValue, int.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new int[]
{
0,
int.MinValue, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
int.MaxValue, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
// Int64 Performance Tests:
private static void RunTests_Int64()
{
Console.WriteLine("\r\nInt64");
const int size = 100000000;
long[] samples = new long[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = Math.Sign(random.Next(-1, 1)) * (long)(random.NextDouble() * long.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new long[]
{
0,
long.MinValue, -1000000000000000000, -999999999999999999, -100000000000000000, -99999999999999999, -10000000000000000, -9999999999999999, -1000000000000000, -999999999999999, -100000000000000, -99999999999999, -10000000000000, -9999999999999, -1000000000000, -999999999999, -100000000000, -99999999999, -10000000000, -9999999999, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
long.MaxValue, 1000000000000000000, 999999999999999999, 100000000000000000, 99999999999999999, 10000000000000000, 9999999999999999, 1000000000000000, 999999999999999, 100000000000000, 99999999999999, 10000000000000, 9999999999999, 1000000000000, 999999999999, 100000000000, 99999999999, 10000000000, 9999999999, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
}
}
long.MaxValue
Log10 jauh lebih baik. Atau hanya di .NET Core?
Int32
dan Int64
menghasilkan kumpulan data yang berbeda, yang mungkin menjelaskan mengapa Int64
menjadi lebih cepat daripada Int32
dalam beberapa kasus. Meskipun, dalam Int32
pengujian dan dalam Int64
pengujian, kumpulan data tidak berubah saat menguji metode penghitungan yang berbeda. Sekarang mengenai .NET Core, saya ragu ada optimasi ajaib di pustaka Matematika yang akan mengubah hasil ini, tetapi saya ingin mendengar lebih banyak tentang itu (jawaban saya sudah sangat besar, mungkin salah satu yang terbesar di SO ;-)
for
loop lebih enumerations
, saya pra-proses dataset acak, dan menghindari penggunaan obat generik, Tugas, Function<>
, Action<>
, atau kerangka pengukuran hitam-kotak). Singkatnya, tetap sederhana. Saya juga mematikan semua aplikasi yang tidak perlu (Skype, Windows Defender, menonaktifkan Anti-Virus, Chrome, cache Microsoft Office, dll).
Bukan langsung C #, tapi rumusnya adalah: n = floor(log10(x)+1)
log10
dalam banyak kasus merupakan fungsi perpustakaan. Mengapa Anda ingin menerapkannya sendiri, dan masalah apa yang Anda temui? log10(x) = log2(x) / log2(10)
, atau secara umum logA(x) = logB(x) / logB(A)
.
Log10(0)
adalah -infinity. Log10 tidak dapat digunakan untuk menghitung jumlah digit angka negatif kecuali Anda menggunakan Math.Abs()
sebelum meneruskan nilai ke Log10. Tapi kemudian Math.Abs(int.MinValue)
melempar Exception ( long.MinValue
juga, dalam kasus Int64). Jika kita mentransmisikan nomor menjadi dua kali lipat sebelum meneruskannya ke Log10, maka itu berfungsi untuk hampir semua nomor kecuali -999999999999999999
(dalam kasus Int64). Apakah Anda tahu rumus untuk menghitung jumlah digit yang menggunakan log10 dan menerima nilai int32 atau int64 sebagai input dan output hanya nilai yang valid?
Jawaban sudah ada di sini berfungsi untuk bilangan bulat tak bertanda tangan, tetapi saya belum menemukan solusi yang baik untuk mendapatkan jumlah digit dari desimal dan ganda.
public static int Length(double number)
{
number = Math.Abs(number);
int length = 1;
while ((number /= 10) >= 1)
length++;
return length;
}
//number of digits in 0 = 1,
//number of digits in 22.1 = 2,
//number of digits in -23 = 2
Anda dapat mengubah jenis masukan dari double
menjadi decimal
jika penting, tetapi desimal juga memiliki batas.
Jawaban Steve benar , tetapi tidak berfungsi untuk bilangan bulat kurang dari 1.
Berikut versi terbaru yang berfungsi untuk negatif:
int digits = n == 0 ? 1 : Math.Floor(Math.Log10(Math.Abs(n)) + 1)
digits = n == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(n)) + 1);
n = int.MinValue
.
Menggunakan rekursi (terkadang ditanyakan pada wawancara)
public int CountDigits(int number)
{
// In case of negative numbers
number = Math.Abs(number);
if (number >= 10)
return CountDigits(number / 10) + 1;
return 1;
}
number = int.MinValue
.
Berikut implementasi menggunakan pencarian biner. Tampaknya menjadi yang tercepat sejauh ini di int32.
Implementasi Int64 dibiarkan sebagai latihan untuk pembaca (!)
Saya mencoba menggunakan Array.BinarySearch daripada melakukan hard-coding pada pohon, tetapi itu sekitar setengah dari kecepatannya.
EDIT: Tabel pencarian jauh lebih cepat daripada pencarian biner, dengan mengorbankan lebih banyak memori. Secara realistis saya mungkin akan menggunakan pencarian biner dalam produksi, tabel pencarian adalah banyak kerumitan untuk mendapatkan kecepatan yang cenderung dibayangi oleh bagian lain dari perangkat lunak.
Lookup-Table: 439 ms
Binary-Search: 1069 ms
If-Chain: 1409 ms
Log10: 1145 ms
While: 1768 ms
String: 5153 ms
Versi tabel pencarian:
static byte[] _0000llll = new byte[0x10000];
static byte[] _FFFFllll = new byte[0x10001];
static sbyte[] _hhhhXXXXdigits = new sbyte[0x10000];
// Special cases where the high DWORD is not enough information to find out how
// many digits.
static ushort[] _lowordSplits = new ushort[12];
static sbyte[] _lowordSplitDigitsLT = new sbyte[12];
static sbyte[] _lowordSplitDigitsGE = new sbyte[12];
static Int32Extensions()
{
// Simple lookup tables for number of digits where value is
// 0000xxxx (0 .. 65535)
// or FFFFxxxx (-1 .. -65536)
precomputePositiveLo16();
precomputeNegativeLo16();
// Hiword is a little more complex
precomputeHiwordDigits();
}
private static void precomputeHiwordDigits()
{
int b = 0;
for(int hhhh = 0; hhhh <= 0xFFFF; hhhh++)
{
// For hiword hhhh, calculate integer value for loword of 0000 and FFFF.
int hhhh0000 = (unchecked(hhhh * 0x10000)); // wrap around on negatives
int hhhhFFFF = hhhh0000 + 0xFFFF;
// How many decimal digits for each?
int digits0000 = hhhh0000.Digits_IfChain();
int digitsFFFF = hhhhFFFF.Digits_IfChain();
// If same number of decimal digits, we know that when we see that hiword
// we don't have to look at the loword to know the right answer.
if(digits0000 == digitsFFFF)
{
_hhhhXXXXdigits[hhhh] = (sbyte)digits0000;
}
else
{
bool negative = hhhh >= 0x8000;
// Calculate 10, 100, 1000, 10000 etc
int tenToThePower = (int)Math.Pow(10, (negative ? digits0000 : digitsFFFF) - 1);
// Calculate the loword of the 10^n value.
ushort lowordSplit = unchecked((ushort)tenToThePower);
if(negative)
lowordSplit = unchecked((ushort)(2 + (ushort)~lowordSplit));
// Store the split point and digits into these arrays
_lowordSplits[b] = lowordSplit;
_lowordSplitDigitsLT[b] = (sbyte)digits0000;
_lowordSplitDigitsGE[b] = (sbyte)digitsFFFF;
// Store the minus of the array index into the digits lookup. We look for
// minus values and use these to trigger using the split points logic.
_hhhhXXXXdigits[hhhh] = (sbyte)(-b);
b++;
}
}
}
private static void precomputePositiveLo16()
{
for(int i = 0; i <= 9; i++)
_0000llll[i] = 1;
for(int i = 10; i <= 99; i++)
_0000llll[i] = 2;
for(int i = 100; i <= 999; i++)
_0000llll[i] = 3;
for(int i = 1000; i <= 9999; i++)
_0000llll[i] = 4;
for(int i = 10000; i <= 65535; i++)
_0000llll[i] = 5;
}
private static void precomputeNegativeLo16()
{
for(int i = 0; i <= 9; i++)
_FFFFllll[65536 - i] = 1;
for(int i = 10; i <= 99; i++)
_FFFFllll[65536 - i] = 2;
for(int i = 100; i <= 999; i++)
_FFFFllll[65536 - i] = 3;
for(int i = 1000; i <= 9999; i++)
_FFFFllll[65536 - i] = 4;
for(int i = 10000; i <= 65535; i++)
_FFFFllll[65536 - i] = 5;
}
public static int Digits_LookupTable(this int n)
{
// Split input into low word and high word.
ushort l = unchecked((ushort)n);
ushort h = unchecked((ushort)(n >> 16));
// If the hiword is 0000 or FFFF we have precomputed tables for these.
if(h == 0x0000)
{
return _0000llll[l];
}
else if(h == 0xFFFF)
{
return _FFFFllll[l];
}
// In most cases the hiword will tell us the number of decimal digits.
sbyte digits = _hhhhXXXXdigits[h];
// We put a positive number in this lookup table when
// hhhh0000 .. hhhhFFFF all have the same number of decimal digits.
if(digits > 0)
return digits;
// Where the answer is different for hhhh0000 to hhhhFFFF, we need to
// look up in a separate array to tell us at what loword the change occurs.
var splitIndex = (sbyte)(-digits);
ushort lowordSplit = _lowordSplits[splitIndex];
// Pick the correct answer from the relevant array, depending whether
// our loword is lower than the split point or greater/equal. Note that for
// negative numbers, the loword is LOWER for MORE decimal digits.
if(l < lowordSplit)
return _lowordSplitDigitsLT[splitIndex];
else
return _lowordSplitDigitsGE[splitIndex];
}
Versi pencarian biner
public static int Digits_BinarySearch(this int n)
{
if(n >= 0)
{
if(n <= 9999) // 0 .. 9999
{
if(n <= 99) // 0 .. 99
{
return (n <= 9) ? 1 : 2;
}
else // 100 .. 9999
{
return (n <= 999) ? 3 : 4;
}
}
else // 10000 .. int.MaxValue
{
if(n <= 9_999_999) // 10000 .. 9,999,999
{
if(n <= 99_999)
return 5;
else if(n <= 999_999)
return 6;
else
return 7;
}
else // 10,000,000 .. int.MaxValue
{
if(n <= 99_999_999)
return 8;
else if(n <= 999_999_999)
return 9;
else
return 10;
}
}
}
else
{
if(n >= -9999) // -9999 .. -1
{
if(n >= -99) // -99 .. -1
{
return (n >= -9) ? 1 : 2;
}
else // -9999 .. -100
{
return (n >= -999) ? 3 : 4;
}
}
else // int.MinValue .. -10000
{
if(n >= -9_999_999) // -9,999,999 .. -10000
{
if(n >= -99_999)
return 5;
else if(n >= -999_999)
return 6;
else
return 7;
}
else // int.MinValue .. -10,000,000
{
if(n >= -99_999_999)
return 8;
else if(n >= -999_999_999)
return 9;
else
return 10;
}
}
}
}
Stopwatch sw0 = new Stopwatch();
sw0.Start();
for(int i = 0; i < size; ++i) samples[i].Digits_BinarySearch();
sw0.Stop();
Console.WriteLine($"Binary-Search: {sw0.ElapsedMilliseconds} ms");
Int64
implementasi untuk LookUpTable? Atau menurut Anda terlalu rumit untuk mengimplementasikannya? Saya ingin menjalankan tes kinerja nanti pada set lengkap.
int i = 855865264;
int NumLen = i.ToString().Length;
string.TrimStart('-')
lebih baik
Buat metode yang mengembalikan semua digit, dan metode lain yang menghitungnya:
public static int GetNumberOfDigits(this long value)
{
return value.GetDigits().Count();
}
public static IEnumerable<int> GetDigits(this long value)
{
do
{
yield return (int)(value % 10);
value /= 10;
} while (value != 0);
}
Ini terasa seperti pendekatan yang lebih intuitif bagi saya saat menangani masalah ini. Saya mencobaLog10
metode ini terlebih dahulu karena kesederhanaannya yang tampak, tetapi metode ini memiliki jumlah kasus sudut dan masalah presisi yang tidak masuk akal.
Saya juga menemukan if
-chain yang diusulkan dalam jawaban lain agak jelek untuk dilihat.
Saya tahu ini bukan metode yang paling efisien, tetapi ini memberi Anda ekstensi lain untuk mengembalikan angka juga untuk penggunaan lain (Anda bisa menandainya private
jika Anda tidak perlu menggunakannya di luar kelas).
Perlu diingat bahwa tanda negatif tidak dianggap sebagai digit.
dikonversi menjadi string dan kemudian Anda dapat menghitung angka tatal angka dengan metode .length. Suka:
String numberString = "855865264".toString();
int NumLen = numberString .Length;
Itu tergantung apa sebenarnya yang ingin Anda lakukan dengan angka tersebut. Anda dapat mengulang melalui digit mulai dari yang terakhir hingga yang pertama seperti ini:
int tmp = number;
int lastDigit = 0;
do
{
lastDigit = tmp / 10;
doSomethingWithDigit(lastDigit);
tmp %= 10;
} while (tmp != 0);
%
untuk mendapatkan digitnya, dan kemudian /=
memotongnya.
Jika hanya untuk memvalidasi Anda dapat melakukan: 887979789 > 99999999
Dengan asumsi pertanyaan Anda mengacu pada int, berikut ini berfungsi untuk negatif / positif dan nol juga:
Math.Floor((decimal) Math.Abs(n)).ToString().Length