C # 'da bir sayının toplam basamak sayısını nasıl alabilirim? Örneğin, 887979789 numarasının 9 hanesi vardır.
C # 'da bir sayının toplam basamak sayısını nasıl alabilirim? Örneğin, 887979789 numarasının 9 hanesi vardır.
Yanıtlar:
Bir dizeye dönüştürmeden şunları deneyebilirsiniz:
Math.Ceiling(Math.Log10(n));
Ysap'ın yorumundan sonraki düzeltme:
Math.Floor(Math.Log10(n) + 1);
n
is 0
sadece dönebilirsiniz 1
:) Çok kolu negatif değerler sadece yerini n
ile Math.Abs(n)
.
Bunu dene:
myint.ToString().Length
İşe yarıyor mu ?
int
, bu yüzden bunun bir sorun olmadığını varsayıyorum.)
Aşağıdaki uzatma yöntemlerinden herhangi biri işi yapacaktır. Hepsi eksi işaretini bir rakam olarak kabul eder ve tüm olası giriş değerleri için doğru şekilde çalışır. Ayrıca .NET Framework ve .NET Core için de çalışırlar. Bununla birlikte, Platform / Çerçeve seçiminize bağlı olarak ilgili performans farklılıkları (aşağıda tartışılmıştır) vardır.
Int32 sürümü:
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;
}
Int64 sürümü:
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;
}
Bu yanıt, her ikisi için yapılan testleri içermektedir Int32
ve Int64
bir dizi kullanarak türleri, 100.000.000
rasgele numune int
/ long
sayı. Rastgele veri kümesi, testler yürütülmeden önce bir diziye önceden işlenir.
4 farklı yöntemleri arasında tutarlılık testleri de idam edildi için MinValue
negatif sınır durumlarda, -1
, 0
, 1
, pozitif sınır vakalar, MaxValue
ve aynı zamanda bütün rasgele veri kümesi için. LOG10 yöntemi HARİÇ yukarıda sağlanan yöntemler için tutarlılık testi başarısız olur (bu daha sonra tartışılacaktır).
Testler yapıldı .NET Framework 4.7.2
ve .NET Core 2.2
; için x86
ve x64
platformlar, 64-bit Intel İşlemci makinede ile Windows 10
ve ile VS2017 v.15.9.17
. Aşağıdaki 4 durum, performans sonuçları üzerinde aynı etkiye sahiptir:
.NET Framework (x86)
Platform = x86
Platform = AnyCPU
, Prefer 32-bit
proje ayarlarında kontrol edilir
.NET Framework (x64)
Platform = x64
Platform = AnyCPU
, Prefer 32-bit
Proje ayarlarında işaretlenmemiş olduğundan
.NET Çekirdeği (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 Çekirdeği (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
Aşağıdaki performans testleri, bir tamsayının alabileceği geniş değer aralığı arasında eşit bir değer dağılımı üretir. Bu, çok sayıda basamaklı değerleri test etme şansının çok daha yüksek olduğu anlamına gelir. Gerçek hayat senaryolarında çoğu değer küçük olabilir, bu nedenle IF-CHAIN daha da iyi performans göstermelidir. Ayrıca işlemci, veri kümenize göre IF-CHAIN kararlarını önbelleğe alır ve optimize eder.
Şöyle @AlanSingfield yorum bölümünde işaret LOG10 usul bir döküm ile sabit zorunda double
iç Math.Abs()
giriş değeri olduğunda durum için int.MinValue
veya long.MinValue
.
Bu soruyu düzenlemeden önce uyguladığım erken performans testleri ile ilgili olarak (zaten milyonlarca kez düzenlenmesi gerekiyordu), IF-CHAIN yönteminin LOG10 yönteminden daha yavaş çalıştığı @ GyörgyKőszeg tarafından belirtilen özel bir durum vardı .
@ AlanSingfield tarafından belirtilen sorunun düzeltilmesinden sonra farkın büyüklüğü çok daha düşük olmasına rağmen, bu yine de oluyor . Bu düzeltme (atama ekleme double
), girdi değeri tam olarak olduğunda bir hesaplama hatasına neden olur -999999999999999999
: 20
bunun yerine LOG10 yöntemi geri döner 19
. LOG10 yöntemi ayrıca if
giriş değerinin sıfır olduğu durum için bir korumaya sahip olmalıdır .
LOG10 yöntemi, tüm değerler için çalışmak oldukça zordur, bu da bundan kaçınmanız gerektiği anlamına gelir. Birisi aşağıdaki tüm tutarlılık testleri için doğru çalışmasını sağlamanın bir yolunu bulursa, lütfen bir yorum gönderin!
WHILE yöntemi aynı zamanda daha hızlı, ancak yine de yavaş olan yeni bir yeniden düzenlenmiş sürümü aldı Platform = x86
(şimdiye kadar nedenini bulamadım).
STRING yöntemi sürekli olarak yavaştır: iştahla boşuna çok fazla bellek ayırır. İlginç bir şekilde, .NET Core'da dize ayırma, .NET Framework'tekinden çok daha hızlı görünüyor. Bunu bildiğim iyi oldu.
IF-CHAIN yöntemi, vakaların% 99,99'unda diğer tüm yöntemlerden daha iyi performans göstermelidir; ve benim kişisel görüşüme göre, en iyi seçiminiz (LOG10 yönteminin doğru çalışması için gerekli tüm ayarlamaları ve diğer iki yöntemin kötü performansını göz önünde bulundurarak).
Son olarak sonuçlar:
Bu sonuçlar donanıma bağlı olduğundan, özel durumunuzda% 100 emin olmanız gerekiyorsa, yine de aşağıdaki performans testlerini kendi bilgisayarınızda çalıştırmanızı tavsiye ederim.
Aşağıda performans testinin kodu ve tutarlılık testi bulunmaktadır. Aynı kod hem .NET Framework hem de .NET Core için kullanılır.
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 için önemli ölçüde daha iyidir. Yoksa sadece .NET Core'da mı?
Int32
ve Int64
ürettiğinin farkında olun; bu , neden bazı durumlarda Int64
olduğundan daha hızlı olduğunu açıklayabilir Int32
. Bununla birlikte, Int32
test içinde ve test içinde Int64
, farklı hesaplama yöntemlerini test ederken veri kümeleri değiştirilmez. Şimdi .NET Core ile ilgili olarak, Matematik kütüphanesinde bu sonuçları değiştirecek sihirli bir optimizasyon olduğundan şüpheliyim, ancak bunun hakkında daha fazlasını duymak isterim (cevabım zaten çok büyük, muhtemelen SO'daki en büyük cevaplardan biri ;-)
for
üzerinde döngüler enumerations
, ben ön işlem rasgele veri kümeleri ve jenerik, Görevler, kullanımını önlemek Function<>
, Action<>
ya da herhangi bir siyah-kutulu ölçüm çerçevesi). Özetle, basit tutun. Ayrıca tüm gereksiz uygulamaları da (Skype, Windows Defender, Anti-Virüs'ü devre dışı bırak, Chrome, Microsoft Office önbelleği vb.) Öldürürüm.
Doğrudan C # değil, ancak formül şudur: n = floor(log10(x)+1)
log10
çoğu durumda bir kitaplık işlevidir. Neden bunu kendiniz uygulamak istiyorsunuz ve hangi sorunlarla karşılaşıyorsunuz? log10(x) = log2(x) / log2(10)
veya genel olarak logA(x) = logB(x) / logB(A)
.
Log10(0)
Log10'u tekrar uygulamak istemedim, yani -infinity. Log10 Math.Abs()
, değeri Log10'a geçirmeden önce kullanmadığınız sürece, negatif sayıların basamak sayısını hesaplamak için kullanılamaz . Ancak daha sonra Math.Abs(int.MinValue)
bir İstisna atar ( long.MinValue
Int64 durumunda da). Sayıyı Log10'a geçmeden önce ikiye katlarsak, -999999999999999999
(Int64 durumunda) hariç hemen hemen tüm sayılar için çalışır . Log10 kullanan ve herhangi bir int32 veya int64 değerini girdi olarak kabul eden ve yalnızca geçerli değerleri çıkaran basamak sayısını hesaplamak için herhangi bir formül biliyor musunuz?
Cevaplar zaten burada işaretsiz tamsayılar için işe yarıyor, ancak ondalıklardan ve çiftlerden basamak sayısı elde etmek için iyi çözümler bulamadım.
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
Sen giriş tipini değiştirebilir double
için decimal
hassas konularda, fakat ondalık de bir sınırı vardır.
Steve'in cevabı doğrudur , ancak 1'den küçük tamsayılar için işe yaramaz.
İşte negatifler için çalışan güncellenmiş bir sürüm:
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
.
Özyineleme kullanma (bazen röportajlarda sorulur)
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
.
İşte ikili arama kullanan bir uygulama. Int32'de şimdiye kadarki en hızlısı gibi görünüyor.
Int64 uygulaması okuyucu için bir alıştırma olarak bırakılmıştır (!)
Ağacı sabit kodlamak yerine Array.BinarySearch kullanmayı denedim, ancak bu hızın yarısı kadardı.
DÜZENLEME: Bir arama tablosu, daha fazla bellek kullanma pahasına, ikili aramadan çok daha hızlıdır. Gerçekçi bir şekilde, muhtemelen üretimde ikili aramayı kullanırdım, arama tablosu, yazılımın diğer bölümleri tarafından gölgede bırakılması muhtemel bir hız kazancı için çok karmaşıktır.
Lookup-Table: 439 ms
Binary-Search: 1069 ms
If-Chain: 1409 ms
Log10: 1145 ms
While: 1768 ms
String: 5153 ms
Arama tablosu sürümü:
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];
}
İkili arama sürümü
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
LookUpTable için uygulamanız var mı? Yoksa bunu uygulamanın çok mu karmaşık olduğunu mu düşünüyorsunuz? Performans testlerini daha sonra tüm sette çalıştırmak istiyorum.
int i = 855865264;
int NumLen = i.ToString().Length;
string.TrimStart('-')
iyisini yap
Tüm basamakları döndüren ve onları sayan bir yöntem oluşturun:
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);
}
Bu sorunla uğraşırken bu bana daha sezgisel bir yaklaşım gibi geldi. Log10
Yöntemi ilk önce görünürdeki basitliği nedeniyle denedim , ancak çok fazla köşe durumu ve hassaslık sorunları var.
Ayrıca if
diğer cevapta önerilen-zinciri bakılması biraz çirkin buldum .
Bunun en verimli yöntem olmadığını biliyorum, ancak diğer kullanımlar için de rakamları döndürmek için size diğer uzantıyı verir ( private
sınıfın dışında kullanmanız gerekmiyorsa işaretleyebilirsiniz ).
Negatif işareti rakam olarak kabul etmediğini unutmayın.
dizgeye dönüştürün ve sonra .length yöntemi ile rakamların sayısını sayabilirsiniz. Sevmek:
String numberString = "855865264".toString();
int NumLen = numberString .Length;
Rakamlarla tam olarak ne yapmak istediğinize bağlı. Sonuncudan ilkine kadar basamakları şu şekilde yineleyebilirsiniz:
int tmp = number;
int lastDigit = 0;
do
{
lastDigit = tmp / 10;
doSomethingWithDigit(lastDigit);
tmp %= 10;
} while (tmp != 0);
%
almak için kullanmalı ve sonra /=
kesmelisiniz.
Eğer sadece doğrulama için yapabiliyorsanız: 887979789 > 99999999
Sorunuzun bir int ile ilgili olduğunu varsayarsak, aşağıdakiler negatif / pozitif ve sıfır için de işe yarar:
Math.Floor((decimal) Math.Abs(n)).ToString().Length