[英]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.