[英]Fastest way to get remaining count to next ceiling ten in C#
我正在執行一組非常大的數字(每個數字13位長度)的操作。
我需要用校驗和驗證每個數字。 校驗和數字將告訴它到下一個十的距離是多少,即:
checksum checksum digit
20 0
21 9
22 8
33 7
34 6
35 5
36 4
37 3
208 2
9 1
數字為EAN-13格式。 因此,最大位數總和= 217(999999999999:無校驗和驗證)。
到目前為止,我認為最快的方法是將數據預加載到int數組中並按索引檢索。
這是最快的方法嗎?
還是在這一點上不再重要了,因為即使執行很多操作,它也將足夠快地執行?
如前所述,將cheksum的校驗和數字值預加載到數組中:
for (int i = 0; i < 220; i += 10)
{
matchValues[i] = 0;
matchValues[i + 1] = 9;
matchValues[i + 2] = 8;
matchValues[i + 3] = 7;
matchValues[i + 4] = 6;
matchValues[i + 5] = 5;
matchValues[i + 6] = 4;
matchValues[i + 7] = 3;
matchValues[i + 8] = 2;
matchValues[i + 9] = 1;
}
這樣,我可以用匹配的校驗和數字matchValues[sum];
覆蓋所有校驗matchValues[sum];
所以:
matchValues [208] = 2;
matchValues [9] = 1;
等等
您可以使用模數來計算與天花板十的距離。 您仍然顯然需要遍歷每個數字。
int modulo = i % 10;
int distanceFromTen = modulo == 0 ? 0 : 10 - modulus;
另一個解決方案是int distanceFromTen = (int)(Math.Ceiling(i / 10d) * 10 - i);
。
我已經針對這兩種方法進行了基准測試:
private static void Main(string[] args)
{
//Console.WriteLine("Checking {0}", i);
int loops = 10;
long averageModulo = 0;
long averageCeiling = 0;
for (int l = 0; l < loops; l++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000000; i++)
{
int modulus = i % 10;
int distanceFromTen = modulus == 0 ? 0 : 10 - modulus;
}
sw.Stop();
Stopwatch swTwo = new Stopwatch();
swTwo.Start();
for (int i = 0; i < 10000000; i++)
{
int distanceFromTenTwo = (int)(Math.Ceiling(i / 10d) * 10 - i);
}
swTwo.Stop();
Console.WriteLine("Modulo: {0} ({1}ms)", sw.ElapsedTicks, sw.ElapsedMilliseconds);
averageModulo += sw.ElapsedTicks;
Console.WriteLine("Math.Ceiling: {0} ({1}ms)", swTwo.ElapsedTicks, swTwo.ElapsedMilliseconds);
averageCeiling += swTwo.ElapsedTicks;
Console.WriteLine("");
}
Console.WriteLine("Average modulo: {0}", averageModulo / loops);
Console.WriteLine("Average ceiling: {0}", averageCeiling / loops);
Console.ReadLine();
}
模運算始終快於上限(可能是由於拳擊)。 話雖如此,兩個操作都非常快。
我認為通過新的編輯,現在的目標是在盡可能短的時間內生成有效的EAN。 這是一些可以在3.5秒內生成000000000000 EAN-13校驗和的代碼(如Wikipedia頁面上所述)。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("");
long start = 0;
long end = 99999999;
long count = end - start + 1;
long[] eans = new long[count];
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(start, end + 1, i => {
eans[i] = GenerateEAN13(i);
});
sw.Stop();
Console.WriteLine("Generation of {0} EAN-13s took {1} ticks ({2} ms)", count, sw.ElapsedTicks, sw.ElapsedMilliseconds);
Console.ReadLine();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long GenerateEAN13(long number)
{
long checksum = 0;
long digit = 0;
long tmp = number;
for (int i = 13; i >= 0; i--)
{
digit = tmp % 10;
tmp = tmp / 10;
checksum += i % 2 == 0 ? digit * 3 : digit;
if (tmp < 10)
break;
}
long modulus = checksum % 10;
checksum = modulus == 0 ? 0 : 10 - modulus;
return number * 10 + checksum;
}
}
為此絕對使用模數。 值的“緩存”將無濟於事,因為通過鍵查找字典值將導致減法中節省的成本,這反過來將調用GetHashCode()
並產生一些開銷:
int distanceFromNextTen = (10 - input % 10) % 10;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.