简体   繁体   English

乘法比求和快吗?

[英]Is multiplication faster than summation?

Consider this ( Project Euler Problem 714 ):考虑一下(欧拉计划问题 714 ):

We call a natural number a duodigit if its decimal representation uses no more than two different digits.如果自然数的十进制表示使用不超过两个不同的数字,我们将其称为双数。 For example, 12, 110 and 33333 are duodigits, while 102 is not.例如,12、110 和 33333 是双位数字,而 102 不是。 It can be shown that every natural number has duodigit multiples.可以证明,每个自然数都有双数倍数。 Let d(n) be the smallest (positive) multiple of the number n that happens to be a duodigit.令 d(n) 是恰好是双数的数字 n 的最小(正)倍数。 For example, d(12)=12, d(102)=1122, d(103)=515, d(290)=11011010 and d(317)=211122.例如,d(12)=12、d(102)=1122、d(103)=515、d(290)=11011010 和 d(317)=211122。

I check if number is duodigit by converting it to string and then get the number of characters in a HashSet<char> ( HashSet is a collection that contains no duplicate elements) of the string.我通过将数字转换为字符串来检查数字是否为双数,然后获取字符串的HashSet<char>HashSet是不包含重复元素的集合)中的字符数。

I have two ways to get the duodigit multiple of the number, if the number is not duodigit itself.如果数字本身不是双数,我有两种方法可以获得数字的双数倍数。

Consider int x = 0;考虑int x = 0; . .

The first way is to keep adding the number to x until x become a duodigit.第一种方法是继续将数字添加到x直到x变成双数。

The second way is to keep adding 1 to x until x * number become a duodigit.第二种方法是不断将 1 加到x直到x * number变成双数。

I used System.Diagnostics.Stopwatch to see which is faster and I got this result:我使用System.Diagnostics.Stopwatch来查看哪个更快,我得到了这个结果:

First way: 8 milliseconds
Second way: 0 milliseconds

My question is "Why the second way is faster?".我的问题是“为什么第二种方式更快?”。 I thought maybe multiplication is faster than summation in this case (Is it?).我认为在这种情况下,乘法可能比求和更快(是吗?)。

Here's the code:这是代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            int number = 12345;

            // First way:
            Stopwatch a = new Stopwatch();
            a.Start();
            int x = number;

            while (new HashSet<char>(x.ToString()).Count > 2)
                x += number;

            a.Stop();


            // Second way:
            Stopwatch b = new Stopwatch();
            b.Start();
            int y = 1;

            while (new HashSet<char>((number * y).ToString()).Count > 2)
                y++;

            b.Stop();

            Console.WriteLine("First way: {0} milliseconds", a.ElapsedMilliseconds);
            Console.WriteLine("Second way: {0} milliseconds", b.ElapsedMilliseconds);
        }
    }
}

And I have tried many times and after warming up but I got the same result each time.我已经尝试了很多次,并且在热身后,但每次都得到相同的结果。

But I got the same results when I tried first and second way separately:但是当我分别尝试第一种和第二种方法时,我得到了相同的结果:

int number = 12345;

// First way:
Stopwatch a = new Stopwatch();
a.Start();
int x = number;

while (new HashSet<char>(x.ToString()).Count > 2)
    x += number;

a.Stop();

Console.WriteLine("First way: {0} milliseconds", a.ElapsedMilliseconds);

// Output:
// First way: 7 milliseconds
int number = 12345;

// Second way:
Stopwatch b = new Stopwatch();
b.Start();
int y = 1;

while (new HashSet<char>((number * y).ToString()).Count > 2)
    y++;

b.Stop();

Console.WriteLine("Second way: {0} milliseconds", b.ElapsedMilliseconds);

// Output:
// Second way: 8 milliseconds

The thing that is going on here is that you are measuring compiler overhead.这里发生的事情是您正在测量编译器开销。 The jitter will compile a method the first time it is run, so the first time any code is run the time will be slightly slower. jitter 会在第一次运行时编译一个方法,所以第一次运行任何代码时时间会稍微慢一些。 Benchmarking need to take this into consideration, and tools like Benchmarking.Net does this for you.基准测试需要考虑到这一点,像Benchmarking.Net这样的工具会为您做到这一点。

A quick and dirty trick is to loop whatever operation is run to ensure it runs for a few seconds, this will reduce the effect of the compiler overhead.一个快速而肮脏的技巧是循环运行任何操作以确保它运行几秒钟,这将减少编译器开销的影响。 Repeating your example a million times produces the times:重复你的例子一百万次会产生时间:

First way: 9627 milliseconds
Second way: 9549 milliseconds

Ie Within measurement errors for this rudimentary method.即在这种基本方法的测量误差范围内。

Multiplication should be slightly slower than addition, but both are some of the fastest instructions you can do.乘法应该比加法稍慢,但两者都是你能做的最快的指令。 The other things in your example, like converting a number to a string or creating a hashSet will utterly dwarf any differnce between addition vs multiplication.您示例中的其他内容,例如将数字转换为字符串或创建 hashSet 将使加法与乘法之间的任何差异完全相形见绌。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM