පයිතන් ඇත්තටම කොතරම් මන්දගාමීද? (නැතහොත් ඔබේ භාෂාව කෙතරම් වේගවත්ද?)


150

මම පයිතන් / NumPy හි ලියා ඇති මෙම කේතය මා සතුව ඇත

from __future__ import division
import numpy as np
import itertools

n = 6
iters = 1000
firstzero = 0
bothzero = 0
""" The next line iterates over arrays of length n+1 which contain only -1s and 1s """
for S in itertools.product([-1, 1], repeat=n+1):
    """For i from 0 to iters -1 """
    for i in xrange(iters):
        """ Choose a random array of length n.
            Prob 1/4 of being -1, prob 1/4 of being 1 and prob 1/2 of being 0. """
        F = np.random.choice(np.array([-1, 0, 0, 1], dtype=np.int8), size=n)
        """The next loop just makes sure that F is not all zeros."""
        while np.all(F == 0):
            F = np.random.choice(np.array([-1, 0, 0, 1], dtype=np.int8), size=n)
        """np.convolve(F, S, 'valid') computes two inner products between
        F and the two successive windows of S of length n."""
        FS = np.convolve(F, S, 'valid')
        if FS[0] == 0:
            firstzero += 1
        if np.all(FS == 0):
            bothzero += 1

print("firstzero: %i" % firstzero)
print("bothzero: %i" % bothzero)

එය අහඹු අරා දෙකක සම්පිණ්ඩනය වාර ගණනක් ගණනය කරයි, එකක් අනෙකට වඩා දිගු, නිශ්චිත සම්භාවිතා ව්‍යාප්තියක් සහිතව, පළමු ස්ථානයේ 0 ක් හෝ ස්ථාන දෙකෙහිම 0 ක් ඇත.

මගේ මිතුරෙකු සමඟ ඔට්ටුවක් ඇති අතර ඔහු පවසන්නේ කේත ලිවීමට පයිතන් භයානක භාෂාවක් බවයි. මගේ පරිගණකයේ 9s අවශ්‍යයි. “නිසි භාෂාවකින්” ලිවුවහොත් එය 100 ගුණයකින් වේගවත් කළ හැකි බව ඔහු පවසයි.

අභියෝගය නම් මෙම කේතයට ඔබ කැමති ඕනෑම භාෂාවකින් 100 ගුණයක් වේගවත් කළ හැකිද යන්න බැලීමයි. මම ඔබේ කේතය පරික්ෂා කර බලා වේගවත්ම සතියක් ජය ගන්නෙමි. යමෙකු 0.09s ට වඩා අඩු වුවහොත් ඔවුන් ස්වයංක්‍රීයව ජය ගන්නා අතර මට අහිමි වේ.

තත්ත්වය

  • පයිතන් . ඇලිස්ටෙයාර් බක්සන් විසින් 30 ගුණයක් වේගවත් කරන්න! වේගවත්ම විසඳුම නොවුනත් ඇත්ත වශයෙන්ම එය මගේ ප්‍රියතමය.
  • ඔක්ටේව් . The තීතෝස් විසින් 100 ගුණයක් වේගවත් කරයි.
  • මලකඩ . Bdbaupp විසින් 500 ගුණයකින් වේගවත් කරන්න.
  • සී ++ . ගයි සර්ටන් විසින් 570 ගුණයකින් වේගවත් කරයි.
  • සී . 727 ගුණයකින් වේගවත් වේ.
  • සී ++ . @ ස්ටෙෆාන් විසින් ඇදහිය නොහැකි තරම් වේගවත්.

වේගවත්ම විසඳුම් දැන් සංවේදී වේලාවට වඩා වේගවත් ය. එබැවින් මම n සිට 10 දක්වා වැඩි කර ඇති අතර හොඳම ඒවා සංසන්දනය කිරීම සඳහා iters = 100000 සකසා ඇත. මෙම මිනුම යටතේ වේගවත්ම වේ.

  • සී . 7.5s byace.
  • සී ++ . 1 ස්ටෙෆාන් විසිනි.

මගේ යන්ත්‍රය වේලාව මගේ යන්ත්‍රය මත ක්‍රියාත්මක වේ. මෙය AMD FX-8350 අට-මූලික සකසනයක සම්මත උබුන්ටු ස්ථාපනයකි. මෙයින් අදහස් කරන්නේ මට ඔබේ කේතය ක්‍රියාත්මක කිරීමට හැකි විය යුතු බවයි.

පසු විපරම් පළ කිරීම මෙම තරගය x100 වේගවත් කිරීමක් ලබා ගැනීම පහසු නොවන බැවින්, ඔවුන්ගේ වේගවත් ගුරු විශේෂ ise දැනුම ලබා ගැනීමට කැමති අය සඳහා මම පසු විපරමක් පළ කර ඇත්තෙමි. පයිතන් ඇත්තටම (II කොටස) කෙතරම් මන්දගාමීදැයි බලන්න.

Answers:


63

සී ++ බිට් මැජික්

සරල RNG සමඟ 0.84ms, c ++ 11 std :: knuth සමඟ 1.67ms

සුළු ඇල්ගොරිතම වෙනස් කිරීම් සහිත මීටර් 0.16 (පහත සංස්කරණය බලන්න)

පයිතන් ක්‍රියාත්මක කිරීම තත්පර 7.97 කින් මගේ රිග් එක මත ධාවනය වේ. එබැවින් ඔබ තෝරා ගන්නා RNG අනුව මෙය 9488 සිට 4772 ගුණයකින් වේගවත් වේ.

#include <iostream>
#include <bitset>
#include <random>
#include <chrono>
#include <stdint.h>
#include <cassert>
#include <tuple>

#if 0
// C++11 random
std::random_device rd;
std::knuth_b gen(rd());

uint32_t genRandom()
{
    return gen();
}
#else
// bad, fast, random.

uint32_t genRandom()
{
    static uint32_t seed = std::random_device()();
    auto oldSeed = seed;
    seed = seed*1664525UL + 1013904223UL; // numerical recipes, 32 bit
    return oldSeed;
}
#endif

#ifdef _MSC_VER
uint32_t popcnt( uint32_t x ){ return _mm_popcnt_u32(x); }
#else
uint32_t popcnt( uint32_t x ){ return __builtin_popcount(x); }
#endif



std::pair<unsigned, unsigned> convolve()
{
    const uint32_t n = 6;
    const uint32_t iters = 1000;
    unsigned firstZero = 0;
    unsigned bothZero = 0;

    uint32_t S = (1 << (n+1));
    // generate all possible N+1 bit strings
    // 1 = +1
    // 0 = -1
    while ( S-- )
    {
        uint32_t s1 = S % ( 1 << n );
        uint32_t s2 = (S >> 1) % ( 1 << n );
        uint32_t fmask = (1 << n) -1; fmask |= fmask << 16;
        static_assert( n < 16, "packing of F fails when n > 16.");


        for( unsigned i = 0; i < iters; i++ )
        {
            // generate random bit mess
            uint32_t F;
            do {
                F = genRandom() & fmask;
            } while ( 0 == ((F % (1 << n)) ^ (F >> 16 )) );

            // Assume F is an array with interleaved elements such that F[0] || F[16] is one element
            // here MSB(F) & ~LSB(F) returns 1 for all elements that are positive
            // and  ~MSB(F) & LSB(F) returns 1 for all elements that are negative
            // this results in the distribution ( -1, 0, 0, 1 )
            // to ease calculations we generate r = LSB(F) and l = MSB(F)

            uint32_t r = F % ( 1 << n );
            // modulo is required because the behaviour of the leftmost bit is implementation defined
            uint32_t l = ( F >> 16 ) % ( 1 << n );

            uint32_t posBits = l & ~r;
            uint32_t negBits = ~l & r;
            assert( (posBits & negBits) == 0 );

            // calculate which bits in the expression S * F evaluate to +1
            unsigned firstPosBits = ((s1 & posBits) | (~s1 & negBits));
            // idem for -1
            unsigned firstNegBits = ((~s1 & posBits) | (s1 & negBits));

            if ( popcnt( firstPosBits ) == popcnt( firstNegBits ) )
            {
                firstZero++;

                unsigned secondPosBits = ((s2 & posBits) | (~s2 & negBits));
                unsigned secondNegBits = ((~s2 & posBits) | (s2 & negBits));

                if ( popcnt( secondPosBits ) == popcnt( secondNegBits ) )
                {
                    bothZero++;
                }
            }
        }
    }

    return std::make_pair(firstZero, bothZero);
}

int main()
{
    typedef std::chrono::high_resolution_clock clock;
    int rounds = 1000;
    std::vector< std::pair<unsigned, unsigned> > out(rounds);

    // do 100 rounds to get the cpu up to speed..
    for( int i = 0; i < 10000; i++ )
    {
        convolve();
    }


    auto start = clock::now();

    for( int i = 0; i < rounds; i++ )
    {
        out[i] = convolve();
    }

    auto end = clock::now();
    double seconds = std::chrono::duration_cast< std::chrono::microseconds >( end - start ).count() / 1000000.0;

#if 0
    for( auto pair : out )
        std::cout << pair.first << ", " << pair.second << std::endl;
#endif

    std::cout << seconds/rounds*1000 << " msec/round" << std::endl;

    return 0;
}

අමතර ලේඛණ සඳහා 64-බිට් වලින් සම්පාදනය කරන්න. සරල සසම්භාවී උත්පාදක යන්ත්රය භාවිතා කරන විට කිසිදු මතක ප්‍රවේශයකින් තොරව ක්‍රියාත්මක වන () ලූප, සියලු විචල්‍යයන් ලේඛනයේ ගබඩා කර ඇත.

එය ක්රියා කරන්නේ කෙසේද: ඒ වෙනුවට ගබඩා වඩා Sහා Fදී මතක අරා වශෙයන්ද, එය uint32_t බිට් ලෙස ගබඩා වේ.
මක්නිසාද යත් S, nඅවම බිටු භාවිතා කරනුයේ කට්ටල බිට් එකක් +1 ලෙසත්, සැකසූ බිට් -1 ක් ලෙසත් ය.
F[-1, 0, 0, 1] හි ව්‍යාප්තියක් නිර්මාණය කිරීමට අවම වශයෙන් බිටු 2 ක් අවශ්‍ය වේ. මෙය සිදු කරනු ලබන්නේ අහඹු බිටු උත්පාදනය කිරීම සහ අවම වශයෙන් වැදගත් (කැඳවනු ලැබූ r) 16 සහ වඩාත්ම වැදගත් බිටු 16 (කැඳවනු ලැබූ ) පරීක්ෂා කිරීමෙනි l. නම් l & ~rඅපි එෆ් +1 බව උපකල්පනය නම්, ~l & rඅපි උපකල්පනය බව Fය -1. නැතහොත් F0 වේ. මෙය අප සොයන ව්‍යාප්තිය ජනනය කරයි.

දැන් අපි S, posBitsමෙහි F == 1 සහ සෑම ස්ථානයක මත මාලාවක් ටිකක් සමග negBitsමෙහි F == -1 සෑම ස්ථානයක මත මාලාවක් ටිකක් සමග.

F * S(මෙහි * ගුණ කිරීම දැක්වෙන) කොන්දේසිය යටතේ +1 ලෙස තක්සේරු කරන බව අපට ඔප්පු කළ හැකිය (S & posBits) | (~S & negBits). F * S-1 ට තක්සේරු කරන සෑම අවස්ථාවකම අපට සමාන තර්කනයක් ජනනය කළ හැකිය . අවසාන වශයෙන්, අපි දන්නවා sum(F * S)0 ට තක්සේරු කරන්නේ නම් සහ එහි ප්‍රති -1 ලය -1 හා + 1 ට සමාන ප්‍රමාණයක් තිබේ නම් පමණි. +1 බිටු සහ බිට් -1 සංසන්දනය කිරීමෙන් මෙය ගණනය කිරීම ඉතා පහසුය.

මෙම ක්‍රියාවට නැංවීම සඳහා බිට් අඟල් 32 ක් භාවිතා වන අතර nපිළිගත් උපරිමය 16 කි. අහඹු උත්පාදක කේතය වෙනස් කිරීමෙන් ක්‍රියාත්මක කිරීම බිටු 31 ක් දක්වාත්, uint32_t වෙනුවට uint64_t භාවිතා කිරීමෙන් බිට් 63 දක්වාත් පරිමාණය කළ හැකිය.

සංස්කරණය කරන්න

පහත දැක්වෙන සංවර්‍ධන ශ්‍රිතය:

std::pair<unsigned, unsigned> convolve()
{
    const uint32_t n = 6;
    const uint32_t iters = 1000;
    unsigned firstZero = 0;
    unsigned bothZero = 0;
    uint32_t fmask = (1 << n) -1; fmask |= fmask << 16;
    static_assert( n < 16, "packing of F fails when n > 16.");


    for( unsigned i = 0; i < iters; i++ )
    {
        // generate random bit mess
        uint32_t F;
        do {
            F = genRandom() & fmask;
        } while ( 0 == ((F % (1 << n)) ^ (F >> 16 )) );

        // Assume F is an array with interleaved elements such that F[0] || F[16] is one element
        // here MSB(F) & ~LSB(F) returns 1 for all elements that are positive
        // and  ~MSB(F) & LSB(F) returns 1 for all elements that are negative
        // this results in the distribution ( -1, 0, 0, 1 )
        // to ease calculations we generate r = LSB(F) and l = MSB(F)

        uint32_t r = F % ( 1 << n );
        // modulo is required because the behaviour of the leftmost bit is implementation defined
        uint32_t l = ( F >> 16 ) % ( 1 << n );

        uint32_t posBits = l & ~r;
        uint32_t negBits = ~l & r;
        assert( (posBits & negBits) == 0 );

        uint32_t mask = posBits | negBits;
        uint32_t totalBits = popcnt( mask );
        // if the amount of -1 and +1's is uneven, sum(S*F) cannot possibly evaluate to 0
        if ( totalBits & 1 )
            continue;

        uint32_t adjF = posBits & ~negBits;
        uint32_t desiredBits = totalBits / 2;

        uint32_t S = (1 << (n+1));
        // generate all possible N+1 bit strings
        // 1 = +1
        // 0 = -1
        while ( S-- )
        {
            // calculate which bits in the expression S * F evaluate to +1
            auto firstBits = (S & mask) ^ adjF;
            auto secondBits = (S & ( mask << 1 ) ) ^ ( adjF << 1 );

            bool a = desiredBits == popcnt( firstBits );
            bool b = desiredBits == popcnt( secondBits );
            firstZero += a;
            bothZero += a & b;
        }
    }

    return std::make_pair(firstZero, bothZero);
}

ධාවන කාලය 0.160-0.161ms දක්වා අඩු කරයි. අතින් ලූප මුදා හැරීම (ඉහත පින්තූරයේ නොමැත) එය 0.150 කරයි. සුළු සුළු n = 10, iter = 100000 නඩුව 250ms යටතේ ධාවනය වේ. අමතර හරයන් උත්තේජනය කිරීමෙන් මට එය මීටර් 50 ට අඩු කර ගත හැකි බව මට විශ්වාසයි, නමුත් එය ඉතා පහසුය.

මෙය සිදු කරනුයේ අභ්‍යන්තර ලූප ශාඛාව නිදහස් කර F සහ S පුඩුවක් මාරු කිරීමෙනි. අවශ්‍ය
නොවන්නේ නම්, bothZeroහැකි සියලුම එස් අරා වලට වඩා අඩුවෙන් ලූප කිරීමෙන් මට ධාවන කාලය මීටර් 0.02 දක්වා අඩු කළ හැකිය.


3
ඔබට gcc හිතකාමී අනුවාදයක් ලබා දිය හැකිද? කරුණාකර ඔබේ විධාන රේඛාව කුමක් විය හැකිද? දැනට මට එය පරීක්ෂා කළ හැකි බව මට විශ්වාස නැත.

මම මේ ගැන කිසිවක් නොදන්නා නමුත් ගූගල් මට පවසන්නේ __builtin_popcount _mm_popcnt_u32 () වෙනුවට ආදේශකයක් විය හැකි බවයි.

3
කේතය යාවත්කාලීන කරන ලදි, නිවැරදි popcnt විධානය තේරීමට #ifdef ස්විචය භාවිතා කරයි. එය සම්පාදනය කර -std=c++0x -mpopcnt -O2බිට් 32 මාදිලියේ ධාවනය කිරීමට මීටර් 1.01 ක් ගතවේ (මා සතුව 64-බිට් ජීසීසී අනුවාදයක් නොමැත).
ස්ටෙෆාන්

ඔබට එය ප්‍රතිදානය මුද්‍රණය කළ හැකිද? එය ඇත්ත වශයෙන්ම දැනට යමක් කරන්නේ දැයි මට විශ්වාස නැත :)

8
ඔබ පැහැදිලිවම මායාකාරියකි. + 1
බර්න්ට්පීසා

76

Python2.7 + Numpy 1.8.1: 10.242 s

ෆෝට්රාන් 90+: 0.029 s 0.003 s 0.022 s 0.010 s

කෙලින්ම ඔයාගේ ඔට්ටුව නැති උනා! මෙහි සමාන්තරකරණ බිංදුවක්වත් නොවේ, කෙළින්ම ෆෝට්රාන් 90+.

සංස්කරණය කරන්න මම අරාව වෙනස් කිරීම සඳහා ගයි සර්ටන්ගේ ඇල්ගොරිතම ගෙන ඇත S(හොඳ සොයා ගැනීම: D). -g -tracebackමෙම කේතය 0.017s දක්වා මන්දගාමී වන සම්පාදක ධජ සක්‍රියව මා සතුව ඇති බව පෙනේ . දැනට, මම මෙය සම්පාදනය කරමින් සිටිමි

ifort -fast -o convolve convolve_random_arrays.f90

නොමැති අයට ifort, ඔබට භාවිතා කළ හැකිය

gfortran -O3 -ffast-math -o convolve convolve_random_arrays.f90

2 වන සංස්කරණය : ධාවන කාලය අඩුවීම යනු මා මීට පෙර යම් වැරැද්දක් කර වැරදි පිළිතුරක් ලබා ගැනීමයි. එය නිවැරදි ආකාරයෙන් කිරීම මන්දගාමී බව පෙනේ. C ++ මට වඩා වේගවත් යැයි මට තවමත් විශ්වාස කළ නොහැක, එබැවින් මම මේ සතියේ යම් කාලයක් ගත කිරීමට යන්නේ එය වේගවත් කිරීම සඳහා මෙයින් කපටිකම ඉවත් කිරීමට ය.

සංස්කරණය 3 : බීඑස්ඩී හි ආර්එන්ජී මත පදනම් වූ එකක් භාවිතා කරමින් ආර්එන්ජී කොටස වෙනස් කිරීම (සාම්පෝ ස්මෝලාන්ඩර් විසින් යෝජනා කරන පරිදි) සහ නිරන්තරයෙන් බෙදීම ඉවත් කිරීමෙන් m1, මම ගයි සර්ටන්ගේ සී ++ පිළිතුරට සමාන වේ. ස්ථිතික අරා භාවිතා කිරීම (ෂාපි යෝජනා කළ පරිදි) ධාවන කාලය C ++ ධාවන කාලය යටතේ පහත වැටේ! ඔව් ෆෝට්රාන්! : ඩී

සංස්කරණය කරන්න 4 පෙනෙන ආකාරයට මෙය සම්පාදනය නොකෙරේ (gfortran සමඟ) සහ නිවැරදිව ක්‍රියාත්මක නොවේ (වැරදි අගයන්) මන්ද පූර්ණ සංඛ්‍යා ඒවායේ සීමාවන් ඉක්මවා යන බැවිනි. එය ක්‍රියාත්මක වන බව සහතික කිරීම සඳහා මම නිවැරදි කිරීම් කර ඇත, නමුත් මේ සඳහා කෙනෙකුට ifort 11+ හෝ gfortran 4.7+ (හෝ වෙනත් සම්පාදකයෙකු iso_fortran_envසහ F2008 int64වර්ගයට ඉඩ දීම ) අවශ්‍ය වේ.

මෙන්න කේතය:

program convolve_random_arrays
   use iso_fortran_env
   implicit none
   integer(int64), parameter :: a1 = 1103515245
   integer(int64), parameter :: c1 = 12345
   integer(int64), parameter :: m1 = 2147483648
   real, parameter ::    mi = 4.656612873e-10 ! 1/m1
   integer, parameter :: n = 6
   integer :: p, pmax, iters, i, nil(0:1), seed
   !integer, allocatable ::  F(:), S(:), FS(:)
   integer :: F(n), S(n+1), FS(2)

   !n = 6
   !allocate(F(n), S(n+1), FS(2))
   iters = 1000
   nil = 0

   !call init_random_seed()

   S = -1
   pmax = 2**(n+1)
   do p=1,pmax
      do i=1,iters
         F = rand_int_array(n)
         if(all(F==0)) then
            do while(all(F==0))
               F = rand_int_array(n)
            enddo
         endif

         FS = convolve(F,S)

         if(FS(1) == 0) then
            nil(0) = nil(0) + 1
            if(FS(2) == 0) nil(1) = nil(1) + 1
         endif

      enddo
      call permute(S)
   enddo

   print *,"first zero:",nil(0)
   print *," both zero:",nil(1)

 contains
   pure function convolve(x, h) result(y)
!x is the signal array
!h is the noise/impulse array
      integer, dimension(:), intent(in) :: x, h
      integer, dimension(abs(size(x)-size(h))+1) :: y
      integer:: i, j, r
      y(1) = dot_product(x,h(1:n-1))
      y(2) = dot_product(x,h(2:n  ))
   end function convolve

   pure subroutine permute(x)
      integer, intent(inout) :: x(:)
      integer :: i

      do i=1,size(x)
         if(x(i)==-1) then
            x(i) = 1
            return
         endif
         x(i) = -1
      enddo
   end subroutine permute

   function rand_int_array(i) result(x)
     integer, intent(in) :: i
     integer :: x(i), j
     real :: y
     do j=1,i
        y = bsd_rng()
        if(y <= 0.25) then
           x(j) = -1
        else if (y >= 0.75) then
           x(j) = +1
        else
           x(j) = 0
        endif
     enddo
   end function rand_int_array

   function bsd_rng() result(x)
      real :: x
      integer(int64) :: b=3141592653
      b = mod(a1*b + c1, m1)
      x = real(b)*mi
   end function bsd_rng
end program convolve_random_arrays

මම හිතන්නේ දැන් ඔබ මන්දගාමී මොලැසස් පයිතන් භාවිතා කිරීම නවතා වේගයෙන් ඉලෙක්ට්‍රෝන-චලනය කළ හැකි ෆෝට්රාන් භාවිතා කරයිද?).


1
කෙසේ වෙතත් සිද්ධි ප්‍රකාශය ජනක යන්ත්‍ර ක්‍රියාකාරිත්වයට වඩා වේගවත් නොවේද? ඔබ යම් ආකාරයක ශාඛා පුරෝකථනය / හැඹිලි රේඛාව / යනාදිය වේගවත් කිරීම අපේක්ෂා නොකරන්නේ නම්?
OrangeDog

17
වේගය එකම යන්ත්‍රයකින් සංසන්දනය කළ යුතුය. OP කේතය සඳහා ඔබට ලැබුණේ කුමන ධාවන කාලයද?
nbubis

3
C ++ පිළිතුර තමන්ගේම සැහැල්ලු අහඹු සංඛ්‍යා උත්පාදක යන්ත්‍රයක් ක්‍රියාත්මක කරයි. ඔබේ පිළිතුර සම්පාදකයා සමඟ එන පෙරනිමිය භාවිතා කර ඇති අතර එය මන්දගාමී විය හැකිද?
සාම්පෝ ස්මෝලාන්ඩර්

3
එසේම, C ++ උදාහරණය ස්ථිතිකව වෙන් කරන ලද අරා භාවිතා කරන බව පෙනේ. සම්පාදනය කරන වේලාවට සකසා ඇති ස්ථාවර දිග අරා භාවිතා කිරීමට උත්සාහ කර එය ඕනෑම වේලාවක රැවුල කපන්නේ දැයි බලන්න.
ෂාපි

1
YleKyleKanos @Lembik හි ගැටළුව වන්නේ කොටුවෙහි පූර්ණ සංඛ්‍යා පැවරුම int64 පිරිවිතරයන් ව්‍යංගයෙන් භාවිතා නොකිරීමයි, එබැවින් ඕනෑම පරිවර්තනයක් සිදු කිරීමට පෙර සංඛ්‍යා int32 වේ. කේතය විය යුත්තේ: integer(int64) :: b = 3141592653_int64සියලු int64 සඳහා. මෙය ෆෝට්රාන් ප්‍රමිතියේ කොටසක් වන අතර ක්‍රමලේඛකයා විසින් වර්ගය ප්‍රකාශිත ක්‍රමලේඛන භාෂාවෙන් අපේක්ෂා කෙරේ. (පා default මාලාවේ පෙරනිමි සැකසුම් මගින් මෙය අභිබවා යා හැකි බව සලකන්න)
ශුන්‍යය

69

පයිතන් 2.7 - 0.882s 0.283s

(OP හි මුල් පිටපත: 6.404s)

සංස්කරණය කරන්න: එෆ් අගයන් පූර්ව ගණනය කිරීමෙන් ස්ටීවන් රුම්බල්ස්කිගේ ප්‍රශස්තිකරණය. මෙම ප්‍රශස්තිකරණය සමඟ cpython විසින් pypy හි 0.365s පරාජය කරයි.

import itertools
import operator
import random

n=6
iters = 1000
firstzero = 0
bothzero = 0

choicesF = filter(any, itertools.product([-1, 0, 0, 1], repeat=n))

for S in itertools.product([-1,1], repeat = n+1):
    for i in xrange(iters):
        F = random.choice(choicesF)
        if not sum(map(operator.mul, F, S[:-1])):
            firstzero += 1
            if not sum(map(operator.mul, F, S[1:])):
                bothzero += 1

print "firstzero", firstzero
print "bothzero", bothzero

OP හි මුල් කේතය එවැනි කුඩා අරා භාවිතා කරයි Numpy භාවිතා කිරීමෙන් කිසිදු ප්‍රතිලාභයක් නොමැත, මෙම පිරිසිදු පයිතන් ක්‍රියාත්මක කිරීම පෙන්නුම් කරන පරිදි. නමුත් මගේ කේතයට වඩා තුන් ගුණයකින් වේගවත් වන මෙම අංකිත ක්‍රියාත්මක කිරීමද බලන්න .

පළමු ප්‍රති result ලය ශුන්‍ය නොවේ නම් ඉතිරි සම්මුතිය මඟ හැරීමෙන්ද මම ප්‍රශස්තිකරණය කරමි.


11
පයිපී සමඟ මෙය තත්පර 0.5 කින් ධාවනය වේ.
ඇලිස්ටෙයාර් බක්ස්ටන්

2
ඔබ n = 10 ලෙස සකසන්නේ නම් ඔබට වඩාත් ඒත්තු ගැන්විය හැකි වේගයක් ලැබෙනු ඇත.

3
තවත් ප්‍රශස්තිකරණයක් වනුයේ හැකියාවන් පූර්ව ගණනය කිරීමයි, Fමන්ද ඒවායින් 4032 ක් පමණි. choicesF = filter(any, itertools.product([-1, 0, 0, 1], repeat=n))ලූප වලින් පිටත අර්ථ දක්වන්න . එවිට අභ්‍යන්තරයේ අර්ථ දක්වන්න F = random.choice(choicesF). එවැනි ප්රවේශයක් සහිත මට 3x වේගවත් කිරීමක් ලැබේ.
ස්ටීවන් රුම්බල්ස්කි

3
සයිතන් හි මෙය සම්පාදනය කරන්නේ කෙසේද? එවිට උපායශීලී ස්ථිතික වර්ග කිහිපයක් එකතු කිරීම?
තානේ බ්‍රිම්හෝල්

2
සෑම දෙයක්ම ශ්‍රිතයකට දමා අවසානයේ එය අමතන්න. එමඟින් නම් දේශීයකරණය වන අතර එමඟින් රිෆ්රාෆ් විසින් යෝජනා කරන ලද ප්‍රශස්තිකරණය ද ක්‍රියා කරයි. එසේම, නිර්මාණය ලූපයෙන් range(iters)පිටතට ගෙනයන්න. සමස්තයක් වශයෙන්, ඔබගේ ඉතා හොඳ පිළිතුරට වඩා මට 7% ක වේගයක් ලැබේ.
මොනිකා නැවත

45

මලකඩ: 0.011s

මුල් පයිතන්: 8.3

මුල් පයිතන්ගේ සෘජු පරිවර්තනයකි.

extern crate rand;

use rand::Rng;

static N: uint = 6;
static ITERS: uint = 1000;

fn convolve<T: Num>(into: &mut [T], a: &[T], b: &[T]) {
    // we want `a` to be the longest array
    if a.len() < b.len() {
        convolve(into, b, a);
        return
    }

    assert_eq!(into.len(), a.len() - b.len() + 1);

    for (n,place) in into.mut_iter().enumerate() {
        for (x, y) in a.slice_from(n).iter().zip(b.iter()) {
            *place = *place + *x * *y
        }
    }
}

fn main() {
    let mut first_zero = 0;
    let mut both_zero = 0;
    let mut rng = rand::XorShiftRng::new().unwrap();

    for s in PlusMinus::new() {
        for _ in range(0, ITERS) {
            let mut f = [0, .. N];
            while f.iter().all(|x| *x == 0) {
                for p in f.mut_iter() {
                    match rng.gen::<u32>() % 4 {
                        0 => *p = -1,
                        1 | 2 => *p = 0,
                        _ => *p = 1
                    }
                }
            }

            let mut fs = [0, .. 2];
            convolve(fs, s, f);

            if fs[0] == 0 { first_zero += 1 }
            if fs.iter().all(|&x| x == 0) { both_zero += 1 }
        }
    }

    println!("{}\n{}", first_zero, both_zero);
}



/// An iterator over [+-]1 arrays of the appropriate length
struct PlusMinus {
    done: bool,
    current: [i32, .. N + 1]
}
impl PlusMinus {
    fn new() -> PlusMinus {
        PlusMinus { done: false, current: [-1, .. N + 1] }
    }
}

impl Iterator<[i32, .. N + 1]> for PlusMinus {
    fn next(&mut self) -> Option<[i32, .. N+1]> {
        if self.done {
            return None
        }

        let ret = self.current;

        // a binary "adder", that just adds one to a bit vector (where
        // -1 is the zero, and 1 is the one).
        for (i, place) in self.current.mut_iter().enumerate() {
            *place = -*place;
            if *place == 1 {
                break
            } else if i == N {
                // we've wrapped, so we want to stop after this one
                self.done = true
            }
        }

        Some(ret)
    }
}
  • සමඟ සම්පාදනය කර ඇත --opt-level=3
  • මගේ මලකඩ සම්පාදකයා මෑත රාත්‍රියකි : ( rustc 0.11-pre-nightly (eea4909 2014-04-24 23:41:15 -0700)හරියටම කිවහොත්)

මලකඩවල රාත්‍රී අනුවාදය භාවිතා කරමින් එය සම්පාදනය කිරීමට මට එය ලැබුණි. කෙසේ වෙතත් මම හිතන්නේ කේතය වැරදියි. ප්‍රතිදානය firstzero 27215 bothzero 12086 ට ආසන්න යමක් විය යුතුය. ඒ වෙනුවට එය 27367 6481 ලබා දෙයි

@ ලෙම්බික්, අපොයි, ඒත්තු ගැන්වීමේදී මගේ aසහ bමිශ්‍ර විය; ස්ථාවර (ධාවන කාලය සැලකිය යුතු ලෙස වෙනස් නොවේ).
huon

4
එය මලකඩවල වේගය ඉතා කදිම නිරූපණයකි.

39

සී ++ (වීඑස් 2012) - 0.026s 0.015s

පයිතන් 2.7.6 / නැම්පි 1.8.1 - 12s

වේගය ~ x800.

කැටි ගැසුණු අරා ඉතා විශාල නම් පරතරය බොහෝ කුඩා වනු ඇත ...

#include <vector>
#include <iostream>
#include <ctime>

using namespace std;

static unsigned int seed = 35;

int my_random()
{
   seed = seed*1664525UL + 1013904223UL; // numerical recipes, 32 bit

   switch((seed>>30) & 3)
   {
   case 0: return 0;
   case 1: return -1;
   case 2: return 1;
   case 3: return 0;
   }
   return 0;
}

bool allzero(const vector<int>& T)
{
   for(auto x : T)
   {
      if(x!=0)
      {
         return false;
      }
   }
   return true;
}

void convolve(vector<int>& out, const vector<int>& v1, const vector<int>& v2)
{
   for(size_t i = 0; i<out.size(); ++i)
   {
      int result = 0;
      for(size_t j = 0; j<v2.size(); ++j)
      {
         result += v1[i+j]*v2[j];
      }
      out[i] = result;
   }
}

void advance(vector<int>& v)
{
   for(auto &x : v)
   {
      if(x==-1)
      {
         x = 1;
         return;
      }
      x = -1;
   }
}

void convolve_random_arrays(void)
{
   const size_t n = 6;
   const int two_to_n_plus_one = 128;
   const int iters = 1000;
   int bothzero = 0;
   int firstzero = 0;

   vector<int> S(n+1);
   vector<int> F(n);
   vector<int> FS(2);

   time_t current_time;
   time(&current_time);
   seed = current_time;

   for(auto &x : S)
   {
      x = -1;
   }
   for(int i=0; i<two_to_n_plus_one; ++i)
   {
      for(int j=0; j<iters; ++j)
      {
         do
         {
            for(auto &x : F)
            {
               x = my_random();
            }
         } while(allzero(F));
         convolve(FS, S, F);
         if(FS[0] == 0)
         {
            firstzero++;
            if(FS[1] == 0)
            {
               bothzero++;
            }
         }
      }
      advance(S);
   }
   cout << firstzero << endl; // This output can slow things down
   cout << bothzero << endl; // comment out for timing the algorithm
}

සටහන් කිහිපයක්:

  • අහඹු ශ්‍රිතය ලූපය ලෙස හඳුන්වනු ලැබේ, එබැවින් මම ඉතා සැහැල්ලු රේඛීය සමෝධානික උත්පාදක යන්ත්‍රයක් සඳහා ගියෙමි (නමුත් එම්එස්බී දෙස නොමසුරුව බැලුවෙමි).
  • මෙය සැබවින්ම ප්‍රශස්ත විසඳුමක් සඳහා ආරම්භක ස්ථානය පමණි.
  • ලිවීමට එතරම් කාලයක් ගත නොවීය ...
  • S හි සියලු අගයන් S[0]"අවම වශයෙන් වැදගත්" ඉලක්කම් බවට මම නැවත කියමි .

ස්වයං අන්තර්ගත උදාහරණයක් සඳහා මෙම ප්‍රධාන කාර්යය එක් කරන්න:

int main(int argc, char** argv)
{
  for(int i=0; i<1000; ++i) // run 1000 times for stop-watch
  {
      convolve_random_arrays();
  }
}

1
ඇත්ත වශයෙන්ම. OP කේතයේ ඇති අරා වල කුඩා ප්‍රමාණයෙන් අදහස් වන්නේ අංක භාවිතා කිරීම ඇත්ත වශයෙන්ම සෘජු පයිතන්ට වඩා මන්දගාමී අනුපිළිවෙලකි.
ඇලිස්ටෙයාර් බක්ස්ටන්

2
දැන් x800 යනු මා කතා කරන්නේ!

ඉතා කදිමයි! ඔබගේ advanceක්‍රියාකාරිත්වය නිසා මම මගේ කේතයේ වේගය වැඩි කර ඇත්තෙමි , එබැවින් මගේ කේතය දැන් ඔබට වඩා වේගවත් ය: P (නමුත් ඉතා හොඳ තරඟයක්!)
කයිල් කැනොස්

1
මැට් පවසන පරිදි @lembik ඔව්. ඔබට C ++ 11 supprt සහ ප්‍රධාන ශ්‍රිතයක් අවශ්‍ය වේ. මෙය ක්‍රියාත්මක කිරීම සඳහා ඔබට තවත් උදව් අවශ්‍ය නම් මට දන්වන්න ...
ගයි සර්ටන්

2
මම මෙය පරීක්‍ෂා කළ අතර std :: vector වෙනුවට සරල අරා භාවිතා කිරීමෙන් තවත් 20% ක් රැවුල බෑමට හැකිය.
PlasmaHH

21

සී

මගේ පරිගණකයේ 0.015s ගනී, OP හි මුල් කේතය ~ 7.7s ගනී. සසම්භාවී අරාව ජනනය කිරීමෙන් සහ එකම පුඩුවක් තුළට කැරකීමෙන් ප්‍රශස්තිකරණය කිරීමට උත්සාහ කළ නමුත් එය විශාල වෙනසක් ඇති බවක් නොපෙනේ.

පළමු අරාව ජනනය කරනු ලබන්නේ පූර්ණ සංඛ්‍යාවක් ගෙන එය ද්විමය ලෙස ලිවීම සහ 1 සිට -1 දක්වා සහ සියල්ල 0 සිට 1 දක්වා වෙනස් කිරීමෙනි. ඉතිරිය ඉතා සරල විය යුතුය.

සංස්කරණය කරන්න: a nලෙස සිටීම වෙනුවට intදැන් අපට nසාර්ව අර්ථ දක්වා ඇති නියතයක් ඇත, එබැවින් අපට int arr[n];ඒ වෙනුවට භාවිතා කළ හැකිය malloc.

Edit2: සාදන ලද rand()ශ්‍රිතය වෙනුවට , මෙය දැන් xorshift PRNG ක්‍රියාත්මක කරයි. අහඹු අරාව ජනනය කිරීමේදී කොන්දේසි සහිත ප්‍රකාශ රාශියක් ඉවත් කරනු ලැබේ.

උපදෙස් සම්පාදනය කරන්න:

gcc -O3 -march=native -fwhole-program -fstrict-aliasing -ftree-vectorize -Wall ./test.c -o ./test

කේතය:

#include <stdio.h>
#include <time.h>

#define n (6)
#define iters (1000)
unsigned int x,y=34353,z=57768,w=1564; //PRNG seeds

/* xorshift PRNG
 * Taken from https://en.wikipedia.org/wiki/Xorshift#Example_implementation
 * Used under CC-By-SA */
int myRand() {
    unsigned int t;
    t = x ^ (x << 11);
    x = y; y = z; z = w;
    return w = w ^ (w >> 19) ^ t ^ (t >> 8);
}

int main() {
    int firstzero=0, bothzero=0;
    int arr[n+1];
    unsigned int i, j;
    x=(int)time(NULL);

    for(i=0; i< 1<<(n+1) ; i++) {
        unsigned int tmp=i;
        for(j=0; j<n+1; j++) {
            arr[j]=(tmp&1)*(-2)+1;
            tmp>>=1;
        }
        for(j=0; j<iters; j++) {
            int randArr[n];
            unsigned int k, flag=0;
            int first=0, second=0;
            do {
                for(k=0; k<n; k++) {
                    randArr[k]=(1-(myRand()&3))%2;
                    flag+=(randArr[k]&1);
                    first+=arr[k]*randArr[k];
                    second+=arr[k+1]*randArr[k];
                }
            } while(!flag);
            firstzero+=(!first);
            bothzero+=(!first&&!second);
        }
    }
    printf("firstzero %d\nbothzero %d\n", firstzero, bothzero);
    return 0;
}

1
මම මෙය පරීක්ෂා කළා. එය ඉතා වේගවත් (උත්සාහ කරන්න n = 10) සහ නිවැරදි පෙනුමක් ලබා දෙයි. ඔබට ස්තුතියි.

මෙම ක්‍රියාත්මක කිරීම මුල් පිටපත අනුගමනය නොකරයි, මන්ද අහඹු දෛශිකය සියලු ශුන්‍ය නම් අවසාන මූලද්‍රව්‍යය පමණක් නැවත ජනනය වේ. මුල් පිටුවේ මුළු දෛශිකය වනු ඇත. ඔබට එම ලූපය do{}while(!flag)හෝ ඒ සඳහා යමක් සම්බන්ධ කළ යුතුය. එය ධාවන කාලය බොහෝ වෙනස් කරනු ඇතැයි මම නොසිතමි (එය වේගවත් කරයි).
ගයි සර්ටන්

@Guy Sirton දැන්වීම පෙර බව continue;පවරා ප්රකාශය මම -1කිරීම k, එසේ kකැමැත්ත පුඩුවක් නැවත 0 සිට.
user12205

1
@ace අහ්! ඔයා හරි. මම ඉතා ඉක්මණින් පරිලෝකනය කළ අතර එය පෙනුමට -=වඩා පෙනුනේ =-:-) ටික වේලාවකින් ලූපය කියවිය හැකි වනු ඇත.
ගයි සර්ටන්

17

ජේ

මම සම්පාදනය කරන ලද කිසිදු භාෂාවක් පරාජය කිරීමට බලාපොරොත්තු නොවෙමි, යමක් මට කියන්නේ මේ සමඟ තත්පර 0.09 ට වඩා අඩු ප්‍රමාණයක් ලබා ගැනීමට ආශ්චර්යමත් යන්ත්‍රයක් අවශ්‍ය බවයි, නමුත් මම කෙසේ හෝ මෙම ජේ ඉදිරිපත් කිරීමට කැමතියි, මන්ද එය ඉතා සිනිඳුයි.

NB. constants
num =: 6
iters =: 1000

NB. convolve
NB. take the multiplication table                */
NB. then sum along the NE-SW diagonals           +//.
NB. and keep the longest ones                    #~ [: (= >./) #/.
NB. operate on rows of higher dimensional lists  " 1
conv =: (+//. #~ [: (= >./) #/.) @: (*/) " 1

NB. main program
S  =: > , { (num+1) # < _1 1                NB. all {-1,1}^(num+1)
F  =: (3&= - 0&=) (iters , num) ?@$ 4       NB. iters random arrays of length num
FS =: ,/ S conv/ F                          NB. make a convolution table
FB =: +/ ({. , *./)"1 ] 0 = FS              NB. first and both zero
('first zero ',:'both zero ') ,. ":"0 FB    NB. output results

මෙය පෙර දශකයේ සිට ලැප්ටොප් එකක 0.5 s පමණ ගත වන අතර, පිළිතුරෙහි ඇති පයිතන් තරම් වේගවත් 20x ක් පමණි. බොහෝ වේලාවක් ගත convකරන්නේ අප එය කම්මැලි ලෙස ලිවීම නිසා (අපි සමස්ත සම්මුතිය ගණනය කරමු) සහ පූර්ණ වශයෙන් ය.

අප ගැන දේවල් දන්නා නිසා Sසහ Fමෙම වැඩසටහන සඳහා නිශ්චිත ප්‍රශස්තිකරණය කිරීමෙන් අපට දේවල් වේගවත් කළ හැකිය. මට ඉදිරිපත් කිරීමට හැකි හොඳම දේ නම්, conv =: ((num, num+1) { +//.)@:(*/)"1විශේෂයෙන් විකර්ණ එකතුවක සිට සම්මුතියේ දීර් est තම මූලද්‍රව්‍යයන්ට අනුරූප වන සංඛ්‍යා දෙක තෝරන්න - එය ආසන්න වශයෙන් කාලය අඩක් කරයි.


6
ජේ සැමවිටම ඉදිරිපත් කිරීම වටී, මිනිසා :)
විටාලි ඩයැට්ලොව්

17

පර්ල් - 9.3X වේගවත් ... 830% වැඩි දියුණු කිරීම

මගේ පුරාණ නෙට්බුක් එකේ, OP කේතය ක්‍රියාත්මක වීමට තත්පර 53 ක් ගතවේ; ඇලිස්ටෙයාර් බක්ස්ටන්ගේ අනුවාදය තත්පර 6.5 ක් පමණ ගත වන අතර පහත දැක්වෙන පර්ල් අනුවාදය තත්පර 5.7 ක් ගතවේ.

use v5.10;
use strict;
use warnings;

use Algorithm::Combinatorics qw( variations_with_repetition );
use List::Util qw( any sum );
use List::MoreUtils qw( pairwise );

my $n         = 6;
my $iters     = 1000;
my $firstzero = 0;
my $bothzero  = 0;

my $variations = variations_with_repetition([-1, 1], $n+1);
while (my $S = $variations->next)
{
  for my $i (1 .. $iters)
  {
    my @F;
    until (@F and any { $_ } @F)
    {
      @F = map +((-1,0,0,1)[rand 4]), 1..$n;
    }

    # The pairwise function doesn't accept array slices,
    # so need to copy into a temp array @S0
    my @S0 = @$S[0..$n-1];

    unless (sum pairwise { $a * $b } @F, @S0)
    {
      $firstzero++;
      my @S1 = @$S[1..$n];  # copy again :-(
      $bothzero++ unless sum pairwise { $a * $b } @F, @S1;
    }
  }
}

say "firstzero ", $firstzero;
say "bothzero ", $bothzero;

12

පයිතන් 2.7 - mkl බන්ධන සහිත අංක 1.8.1 - 0.086s

(OP හි මුල් පිටපත: 6.404s) (බක්ස්ටන්ගේ පිරිසිදු පයිතන්: 0.270s)

import numpy as np
import itertools

n=6
iters = 1000

#Pack all of the Ses into a single array
S = np.array( list(itertools.product([-1,1], repeat=n+1)) )

# Create a whole array of test arrays, oversample a bit to ensure we 
# have at least (iters) of them
F = np.random.rand(int(iters*1.1),n)
F = ( F < 0.25 )*-1 + ( F > 0.75 )*1
goodrows = (np.abs(F).sum(1)!=0)
assert goodrows.sum() > iters, "Got very unlucky"
# get 1000 cases that aren't all zero
F = F[goodrows][:iters]

# Do the convolution explicitly for the two 
# slots, but on all of the Ses and Fes at the 
# same time
firstzeros = (F[:,None,:]*S[None,:,:-1]).sum(-1)==0
secondzeros = (F[:,None,:]*S[None,:,1:]).sum(-1)==0

firstzero_count = firstzeros.sum()
bothzero_count = (firstzeros * secondzeros).sum()
print "firstzero", firstzero_count
print "bothzero", bothzero_count

බක්ස්ටන් පෙන්වා දෙන පරිදි, OP හි මුල් කේතය එවැනි කුඩා අරා භාවිතා කරයි. Numpy භාවිතා කිරීමෙන් කිසිදු ප්‍රතිලාභයක් නොමැත. මෙම ක්‍රියාවට නැංවීම මඟින් සියලු එෆ් සහ එස් සිද්ධීන් එකවරම අරාව නැඹුරු ආකාරයකින් සිදු කරයි. මෙය පයිතන් සඳහා mkl බන්ධන සමඟ සංයෝජනය වීමෙන් ඉතා වේගයෙන් ක්‍රියාත්මක වේ.

පුස්තකාල පැටවීම සහ පරිවර්තකය ආරම්භ කිරීම සඳහා තත්පර 0.076 ක් ගත වන බැවින් සත්‍ය ගණනය කිරීම තත්පර ++ ක් ගතවන අතර එය C ++ විසඳුමට සමාන වේ.


Mkl බන්ධන යනු කුමක්ද සහ මම ඒවා උබුන්ටු මත ලබා ගන්නේ කෙසේද?

ධාවනය python -c "import numpy; numpy.show_config()"ආදිය numpy ඔබේ අනුවාදය blas / ලෝක භාෂා සිතියම / mkl එරෙහිව සකස් නම් ඔබට පෙන්වා දෙනු ඇත, ඇට්ලස් numpy බව නිදහස් කඩිනම් ගණිත පැකේජයේ හා සම්බන්ධ කර ගත හැකි , ඉන්ටෙල් MKL ඔබ සාමාන්යයෙන් (ඔබ ශාස්ත්රාලීය ඉන්නේ නම්) සඳහා ගෙවීමට ඇති හා numpy / scipy සම්බන්ධ කළ හැකි .
alemi

පහසු ක්‍රමයක් සඳහා, ඇනකොන්ඩා පයිතන් බෙදා හැරීම භාවිතා කර වේගවත් පැකේජය භාවිතා කරන්න . නැතහොත් එන්තෝට් බෙදාහැරීම භාවිතා කරන්න .
alemi

ඔබ Windows මත නම්, හුදෙක් සිට numpy බාගත මෙතන . එම්.කේ.එල් සමඟ සම්බන්ධිත පූර්ව සම්පාදිත අංක ස්ථාපකයන්.
ව්‍යාජ නම

9

MATLAB 0.024s

පරිගණක 1

  • මුල් කේතය: ~ 3.3 s
  • ඇලිස්ටාර් බක්ස්ටන්ගේ කේතය: ~ 0.51 s
  • ඇලිස්ටාර් බක්ස්ටන්ගේ නව කේතය: ~ 0.25 s
  • මැට්ලැබ් කේතය: ~ 0.024 s (මැට්ලැබ් දැනටමත් ක්‍රියාත්මකයි)

පරිගණක 2

  • මුල් කේතය: 66 6.66 s
  • ඇලිස්ටාර් බක්ස්ටන්ගේ කේතය: ~ 0.64 s
  • ඇලිස්ටාර් බක්ස්ටන්ගේ නව කේතය :?
  • මැට්ලැබ්: ~ 0.07 s (මැට්ලැබ් දැනටමත් ක්‍රියාත්මකයි)
  • ඔක්ටේව්: ~ 0.07 s

මම තීරණය කළා ඔහ් මෙතරම් මන්දගාමී මැට්ලැබ් උත්සාහ කර බලන්න. කෙසේ දැයි ඔබ දන්නේ නම්, ඔබට බොහෝ ලූප (මැට්ලැබ් හි) ඉවත් කළ හැකිය, එමඟින් එය වේගවත් කරයි. කෙසේ වෙතත්, මතක අවශ්‍යතා ලූප් විසඳුම් වලට වඩා වැඩි නමුත් ඔබට විශාල අරා නොමැති නම් මෙය ගැටළුවක් නොවනු ඇත ...

function call_convolve_random_arrays
tic
convolve_random_arrays
toc
end

function convolve_random_arrays

n = 6;
iters = 1000;
firstzero = 0;
bothzero = 0;

rnd = [-1, 0, 0, 1];

S = -1 *ones(1, n + 1);

IDX1 = 1:n;
IDX2 = IDX1 + 1;

for i = 1:2^(n + 1)
    F = rnd(randi(4, [iters, n]));
    sel = ~any(F,2);
    while any(sel)
        F(sel, :) = rnd(randi(4, [sum(sel), n]));
        sel = ~any(F,2);
    end

    sum1 = F * S(IDX1)';
    sel = sum1 == 0;
    firstzero = firstzero + sum(sel);

    sum2 = F(sel, :) * S(IDX2)';
    sel = sum2 == 0;
    bothzero = bothzero + sum(sel);

    S = permute(S); 
end

fprintf('firstzero %i \nbothzero %i \n', firstzero, bothzero);

end

function x = permute(x)

for i=1:length(x)
    if(x(i)==-1)
        x(i) = 1;
            return
    end
        x(i) = -1;
end

end

මෙන්න මම කරන දේ:

  • එස් හරහා ප්‍රේරණය වීමට කයිල් කැනෝස් ශ්‍රිතය භාවිතා කරන්න
  • සියලුම n * iters අහඹු සංඛ්‍යා එකවර ගණනය කරන්න
  • 1 සිට 4 දක්වා සිතියම [-1 0 0 1]
  • matrix ගුණනය භාවිතා කරන්න (මූලද්‍රව්‍ය වශයෙන් එකතුව (F * S (1: 5)) F * S (1: 5) හි අනුකෘතියේ ගුණ කිරීම හා සමාන වේ.
  • දෙකම සඳහා: පළමු කොන්දේසිය සම්පුර්ණ කරන සාමාජිකයින් පමණක් ගණනය කරන්න

මම හිතන්නේ ඔබට මැට්ලැබ් නැත, එය ඉතා නරක බැවින් එය සංසන්දනය කරන්නේ කෙසේදැයි බැලීමට මා කැමති වනු ඇත ...

(ඔබ එය ක්‍රියාත්මක කරන පළමු අවස්ථාව ශ්‍රිතය මන්දගාමී විය හැක.)


හොඳයි, මට අෂ්ටකයක් තිබේ නම් ඔබට එය ක්‍රියාත්මක කළ හැකි නම් ...?

මට එය උත්සාහ කර බලන්න පුළුවන් - මම කවදාවත් අෂ්ටක සමඟ වැඩ කළේ නැහැ.
mathause

හරි, මම කේතය call_convolve_random_arrays.m නම් ගොනුවකට දමා අෂ්ටකයේ සිට ඇමතුමක් ගත්තොත් මට එය අෂ්ටකයේ මෙන් ක්‍රියාත්මක කළ හැකිය.
mathause

ඇත්ත වශයෙන්ම එය ඕනෑම දෙයක් කිරීමට ලබා ගැනීමට තවත් කේත කිහිපයක් අවශ්‍යද? මම "octave call_convolve_random_arrays.m" කරන විට එය කිසිවක් ප්‍රතිදානය නොකරයි. Bpaste.net/show/JPtLOCeI3aP3wc3F3aGf

කණගාටුයි, අෂ්ටකය විවෘත කර එය ක්‍රියාත්මක කිරීමට උත්සාහ කරන්න. එය firstzero, bothzero සහ ක්‍රියාත්මක කිරීමේ වේලාව පෙන්විය යුතුය.
mathause

7

ජූලියා: 0.30 s

ඔප්ස් පයිතන්: 21.36 s (Core2 duo)

71x වේගවත් කිරීම

function countconv()                                                                                                                                                           
    n = 6                                                                                                                                                                      
    iters = 1000                                                                                                                                                               
    firstzero = 0                                                                                                                                                              
    bothzero = 0                                                                                                                                                               
    cprod= Iterators.product(fill([-1,1], n+1)...)                                                                                                                             
    F=Array(Float64,n);                                                                                                                                                        
    P=[-1. 0. 0. 1.]                                                                                                                                                                                                                                                                                                             

    for S in cprod                                                                                                                                                             
        Sm=[S...]                                                                                                                                                              
        for i = 1:iters                                                                                                                                                        
            F=P[rand(1:4,n)]                                                                                                                                                  
            while all(F==0)                                                                                                                                                   
                F=P[rand(1:4,n)]                                                                                                                                              
            end                                                                                                                                                               
            if  dot(reverse!(F),Sm[1:end-1]) == 0                                                                                                                           
                firstzero += 1                                                                                                                                                 
                if dot(F,Sm[2:end]) == 0                                                                                                                              
                    bothzero += 1                                                                                                                                              
                end                                                                                                                                                            
            end                                                                                                                                                                
        end                                                                                                                                                                    
    end
    return firstzero,bothzero
end

මම අර්මාන්ගේ ජූලියා පිළිතුරෙහි යම් යම් වෙනස් කිරීම් සිදු කළෙමි: පළමුව, මම එය ශ්‍රිතයක් තුළට ඔතා, ගෝලීය විචල්‍යයන් ජූලියාගේ අනුමානය සහ JIT සඳහා අපහසු වන හෙයින්: ගෝලීය විචල්‍යයකට ඕනෑම වේලාවක එහි වර්ගය වෙනස් කළ හැකි අතර සෑම මෙහෙයුමක්ම පරීක්ෂා කළ යුතුය . ඉන්පසුව, මම නිර්නාමික කාර්යයන් සහ අරාව අවබෝධය ඉවත් කළෙමි. ඒවා ඇත්තෙන්ම අවශ්‍ය නොවන අතර ඒවා තවමත් මන්දගාමී ය. ජූලියා දැන් පහළ මට්ටමේ වියුක්ත කිරීම් සමඟ වේගවත් ය.

එය වේගවත් කිරීමට තවත් බොහෝ ක්‍රම තිබේ, නමුත් මෙය හොඳ කාර්යයක් කරයි.


ඔබ REPL හි වේලාව මනිනවාද නැතිනම් සම්පූර්ණ ගොනුව විධාන රේඛාවෙන් ධාවනය කරනවාද?
ආදිත්‍ය

දෙකම REPL වෙතින්.
user20768

6

හරි, මම මෙය පළ කරන්නේ ජාවා මෙහි නිරූපණය කළ යුතු යැයි මට හැඟෙන නිසාය. මම වෙනත් භාෂාවන් සමඟ භයානක වන අතර ගැටලුව හරියටම තේරුම් නොගත් බවට මම පාපොච්චාරණය කරමි, එබැවින් මෙම කේතය නිවැරදි කිරීමට මට යම් උපකාරයක් අවශ්‍ය වනු ඇත. මම කේතයේ බොහෝ උදාහරණ සොරකම් කර, පසුව අනෙක් අයගෙන් ස්නිපෙට් කිහිපයක් ණයට ගත්තෙමි. මම හිතන්නේ එය ව්‍යාජ දෙයක් නොවේ ...

මම පෙන්වා දීමට කැමති එක් දෙයක් නම්, ධාවන වේලාවේදී ප්‍රශස්තිකරණය කරන භාෂාවන් පූර්ණ වේගයට නැගීමට කිහිප වතාවක් හෝ බොහෝ වාරයක් ධාවනය කළ යුතු බවයි. මම හිතන්නේ සම්පූර්ණයෙන්ම ප්‍රශස්තිකරණය කළ වේගය (හෝ අවම වශයෙන් සාමාන්‍ය වේගය) ගැනීම යුක්ති සහගත ය, මන්ද ඔබ වේගයෙන් ධාවනය කිරීමට සැලකිලිමත් වන බොහෝ දේ කිහිප වතාවක් ධාවනය වනු ඇත.

කේතය තවමත් සවි කළ යුතුව ඇත, නමුත් මට ලැබිය යුතු වේලාවන් බැලීමට මම එය කෙසේ හෝ ධාවනය කළෙමි.

උබුන්ටු මත ඉන්ටෙල් (ආර්) ෂෝන් (ආර්) සීපීයූ ඊ 3-1270 වී 2 @ 3.50GHz මත 1000 වතාවක් ධාවනය වන ප්‍රති results ල මෙන්න:

server: / tmp # time java8 -cp. පරීක්ෂක

firstzero 40000

bothzero 20000

පළමු ධාවන කාලය: 41 ms අවසන් ධාවන කාලය: 4 ms

තාත්වික 0m5.014s පරිශීලක 0m4.664s sys 0m0.268s

මෙන්න මගේ කපටි කේතය:

public class Tester 
{
    public static void main( String[] args )
    {
        long firstRunTime = 0;
        long lastRunTime = 0;
        String testResults = null;
        for( int i=0 ; i<1000 ; i++ )
        {
            long timer = System.currentTimeMillis();
            testResults = new Tester().runtest();
            lastRunTime = System.currentTimeMillis() - timer;
            if( i ==0 )
            {
                firstRunTime = lastRunTime;
            }
        }
        System.err.println( testResults );
        System.err.println( "first run time: " + firstRunTime + " ms" );
        System.err.println( "last run time: " + lastRunTime + " ms" );
    }

    private int x,y=34353,z=57768,w=1564; 

    public String runtest()
    {
        int n = 6;
        int iters = 1000;
        //#define iters (1000)
        //PRNG seeds

        /* xorshift PRNG
         * Taken from https://en.wikipedia.org/wiki/Xorshift#Example_implementation
         * Used under CC-By-SA */

            int firstzero=0, bothzero=0;
            int[] arr = new int[n+1];
            int i=0, j=0;
            x=(int)(System.currentTimeMillis()/1000l);

            for(i=0; i< 1<<(n+1) ; i++) {
                int tmp=i;
                for(j=0; j<n+1; j++) {
                    arr[j]=(tmp&1)*(-2)+1;
                    tmp>>=1;
                }
                for(j=0; j<iters; j++) {
                    int[] randArr = new int[n];
                    int k=0;
                    long flag = 0;
                    int first=0, second=0;
                    do {
                        for(k=0; k<n; k++) {
                            randArr[k]=(1-(myRand()&3))%2;
                            flag+=(randArr[k]&1);
                            first+=arr[k]*randArr[k];
                            second+=arr[k+1]*randArr[k];
                        }
                    } while(allzero(randArr));
                    if( first == 0 )
                    {
                        firstzero+=1;
                        if( second == 0 )
                        {
                            bothzero++;
                        }
                    }
                }
            }
         return ( "firstzero " + firstzero + "\nbothzero " + bothzero + "\n" );
    }

    private boolean allzero(int[] arr)
    {
       for(int x : arr)
       {
          if(x!=0)
          {
             return false;
          }
       }
       return true;
    }

    public int myRand() 
    {
        long t;
        t = x ^ (x << 11);
        x = y; y = z; z = w;
        return (int)( w ^ (w >> 19) ^ t ^ (t >> 8));
    }
}

මම පයිතන් උත්ශ්‍රේණිගත කිරීමෙන් පසුව සහ පයිතන්-අංකී ස්ථාපනය කිරීමෙන් පසු පයිතන් කේතය ධාවනය කිරීමට උත්සාහ කළ නමුත් මට මෙය ලැබුණි:

server:/tmp# python tester.py
Traceback (most recent call last):
  File "peepee.py", line 15, in <module>
    F = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = n)
AttributeError: 'module' object has no attribute 'choice'

අදහස්: මිණුම් සලකුණු කිරීම සඳහා කිසි විටෙකත් භාවිතා නොකරන්නcurrentTimeMillis (පද්ධතියේ නැනෝ අනුවාදය භාවිතා කරන්න) සහ JIT සම්බන්ධ කර ගැනීමට 1k ලකුණු ප්‍රමාණවත් නොවනු ඇත (සේවාදායකයා සඳහා 1.5k සහ සේවාදායකය සඳහා 10k පෙරනිමිය වනු ඇත, නමුත් ඔබ බොහෝ විට myRand අමතන්න. JITed මඟින් මෙහි ක්‍රියාකාරී විය හැකි ඇමතුම් තොගය සම්පාදනය කිරීමට හේතු විය හැක) .සමහර විට දුර්වල PNRG වංචා කරයි, නමුත් C ++ විසඳුම සහ වෙනත් අයද එසේ කරයි, එබැවින් එය අසාධාරණ නොවන බව මම අනුමාන කරමි.
Voo

කවුළු මත ඔබ වත්මන් ටයිම්මිලිස් වළක්වා ගත යුතුය, නමුත් ලිනක්ස් සඳහා ඉතා සියුම් කැටිති මිනුම් සඳහා ඔබට නැනෝ කාලය අවශ්‍ය නොවන අතර නැනෝ වේලාව ලබා ගැනීමේ ඇමතුම මිලි වලට වඩා මිල අධිකය. එබැවින් ඔබ එය කිසි විටෙකත් භාවිතා නොකළ යුතු බවට මම බෙහෙවින් එකඟ නොවෙමි.
ක්‍රිස් සෙලීන්

ඉතින් ඔබ එක් විශේෂිත මෙහෙයුම් පද්ධතියක් සහ ජේවීඑම් ක්‍රියාත්මක කිරීම සඳහා ජාවා කේතය ලියනවාද? ඇත්ත වශයෙන්ම ඔබ භාවිතා කරන්නේ කුමන මෙහෙයුම් gettimeofday(&time, NULL)පද්ධතියදැයි මට විශ්වාස නැත , මන්ද මම මගේ හොට්ස්පොට් ඩෙව් ගස පරීක්ෂා කර ඇති අතර මිලි තත්පර සඳහා ලිනක්ස් භාවිතා කරන්නේ ඒකාකාරී නොවන අතර නිරවද්‍යතා සහතිකයක් ලබා නොදේ (එබැවින් සමහර වේදිකා / කර්නල් වල හරියටම සමාන වේ වත්මන් ටයිම්මිලිස් වින්ඩෝස් ක්‍රියාත්මක කිරීම වැනි ගැටළු - එබැවින් යමෙකුගේ දඩය හෝ එසේ නොවේ). අනෙක් අතට නැනෝ ටයිම් clock_gettime(CLOCK_MONOTONIC, &tp)භාවිතා කරන්නේ ලිනක්ස් හි මිණුම් සලකුණු කිරීමේදී භාවිතා කළ යුතු නිවැරදි දෙයයි.
Voo

මම ඕනෑම ලිනක්ස් ඩිස්ට්‍රෝ හෝ කර්නලයක ජාවා කේතනය කර ඇති බැවින් එය කිසි විටෙකත් මට ගැටලුවක් වී නොමැත.
ක්‍රිස් සෙලීන්

6

ගොලාන්ග් කේතයේ මගේ යන්ත්‍රයේ 45X පයිතන් අනුවාදය:

package main

import (
"fmt"
"time"
)

const (
n     = 6
iters = 1000
)

var (
x, y, z, w = 34353, 34353, 57768, 1564 //PRNG seeds
)

/* xorshift PRNG
 * Taken from https://en.wikipedia.org/wiki/Xorshift#Example_implementation
 * Used under CC-By-SA */
func myRand() int {
var t uint
t = uint(x ^ (x << 11))
x, y, z = y, z, w
w = int(uint(w^w>>19) ^ t ^ (t >> 8))
return w
}

func main() {
var firstzero, bothzero int
var arr [n + 1]int
var i, j int
x = int(time.Now().Unix())

for i = 0; i < 1<<(n+1); i = i + 1 {
    tmp := i
    for j = 0; j < n+1; j = j + 1 {
        arr[j] = (tmp&1)*(-2) + 1
        tmp >>= 1
    }
    for j = 0; j < iters; j = j + 1 {
        var randArr [n]int
        var flag uint
        var k, first, second int
        for {
            for k = 0; k < n; k = k + 1 {
                randArr[k] = (1 - (myRand() & 3)) % 2
                flag += uint(randArr[k] & 1)
                first += arr[k] * randArr[k]
                second += arr[k+1] * randArr[k]
            }
            if flag != 0 {
                break
            }
        }
        if first == 0 {
            firstzero += 1
            if second == 0 {
                bothzero += 1
            }
        }
    }
}
println("firstzero", firstzero, "bothzero", bothzero)
}

සහ ඉහළින් පිටපත් කරන ලද පහත පයිතන් කේත:

import itertools
import operator
import random

n=6
iters = 1000
firstzero = 0
bothzero = 0

choicesF = filter(any, itertools.product([-1, 0, 0, 1], repeat=n))

for S in itertools.product([-1,1], repeat = n+1):
    for i in xrange(iters):
        F = random.choice(choicesF)
        if not sum(map(operator.mul, F, S[:-1])):
            firstzero += 1
            if not sum(map(operator.mul, F, S[1:])):
                bothzero += 1

print "firstzero", firstzero
print "bothzero", bothzero

සහ පහත කාලය:

$time python test.py
firstzero 27349
bothzero 12125

real    0m0.477s
user    0m0.461s
sys 0m0.014s

$time ./hf
firstzero 27253 bothzero 12142

real    0m0.011s
user    0m0.008s
sys 0m0.002s

1
ඔබ භාවිතා කිරීම ගැන සිතුවාද "github.com/yanatan16/itertools"? බහු ගොරෝටයින් වල මෙය හොඳ වනු ඇතැයි ඔබ කියනවාද?
ymg

6

හැස්කෙල්: එක් හරයකට x 2000x වේගවත් කිරීම

'Ghc -O3 -funbox -rict-fields -threaded -fllvm' සමඟ සම්පාදනය කර '+ RTS -Nk' සමඟ ධාවනය කරන්න, එහිදී k යනු ඔබේ යන්ත්‍රයේ ඇති හර ගණනයි.

import Control.Parallel.Strategies
import Data.Bits
import Data.List
import Data.Word
import System.Random

n = 6 :: Int
iters = 1000 :: Int

data G = G !Word !Word !Word !Word deriving (Eq, Show)

gen :: G -> (Word, G)
gen (G x y z w) = let t  = x `xor` (x `shiftL` 11)
                      w' = w `xor` (w `shiftR` 19) `xor` t `xor` (t `shiftR` 8)
                  in (w', G y z w w')  

mask :: Word -> Word
mask = (.&.) $ (2 ^ n) - 1

gen_nonzero :: G -> (Word, G)
gen_nonzero g = let (x, g') = gen g 
                    a = mask x
                in if a == 0 then gen_nonzero g' else (a, g')


data F = F {zeros  :: !Word, 
            posneg :: !Word} deriving (Eq, Show)

gen_f :: G -> (F, G)       
gen_f g = let (a, g')  = gen_nonzero g
              (b, g'') = gen g'
          in  (F a $ mask b, g'')

inner :: Word -> F -> Int
inner s (F zs pn) = let s' = complement $ s `xor` pn
                        ones = s' .&. zs
                        negs = (complement s') .&. zs
                    in popCount ones - popCount negs

specialised_convolve :: Word -> F -> (Int, Int)
specialised_convolve s f@(F zs pn) = (inner s f', inner s f) 
    where f' = F (zs `shiftL` 1) (pn `shiftL` 1)

ss :: [Word]
ss = [0..2 ^ (n + 1) - 1]

main_loop :: [G] -> (Int, Int)
main_loop gs = foldl1' (\(fz, bz) (fz', bz') -> (fz + fz', bz + bz')) . parMap rdeepseq helper $ zip ss gs
    where helper (s, g) = go 0 (0, 0) g
                where go k u@(fz, bz) g = if k == iters 
                                              then u 
                                              else let (f, g') = gen_f g
                                                       v = case specialised_convolve s f
                                                               of (0, 0) -> (fz + 1, bz + 1)
                                                                  (0, _) -> (fz + 1, bz)
                                                                  _      -> (fz, bz)
                                                   in go (k + 1) v g'

seed :: IO G                                        
seed = do std_g <- newStdGen
          let [x, y, z, w] = map fromIntegral $ take 4 (randoms std_g :: [Int])
          return $ G x y z w

main :: IO ()
main = (sequence $ map (const seed) ss) >>= print . main_loop

2
ඒ නිසා මධ්යය 4 එය 9000 ඉවරයි ! නිවැරදි විය හැකි ක්‍රමයක් නොමැත.
සීස් ටිමර්මන්

ඇම්ඩාල්ගේ නියමය අනුව සමාන්තරකරණ වේගය සමාන්තර සැකසුම් ඒකක සංඛ්‍යාවට රේඛීය නොවේ. ඒ වෙනුවට ඔවුන් සපයන්නේ අඳුරු ප්‍රතිලාභ පමණි
xaedes

axaedes වේගවත් කිරීම මූලික වශයෙන් අඩු හරයන් සඳහා රේඛීය ලෙස පෙනේ
user1502040

5

සී # 0.135s

C # ඇලිස්ටෙයාර් බක්ස්ටන්ගේ සරල පයිතන් මත පදනම්ව : 0.278s
සමාන්තරගත C #: 0.135s
පයිතන් ප්‍රශ්නයෙන්: 5.907s
ඇලිස්ටෙයාර්ගේ සරල පයිතන්: 0.853s

මෙම ක්‍රියාවට නැංවීම නිවැරදි යැයි මට විශ්වාස නැත - එහි ප්‍රතිදානය වෙනස් වේ, ඔබ ප්‍රති the ල පහළින් බැලුවහොත්.

නිසැකවම වඩා ප්‍රශස්ත ඇල්ගොරිතම ඇත. මම තීරණය කළා පයිතන්ට සමාන ඇල්ගොරිතමයක් භාවිතා කිරීමට.

තනි නූල් සී

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConvolvingArrays
{
    static class Program
    {
        static void Main(string[] args)
        {
            int n=6;
            int iters = 1000;
            int firstzero = 0;
            int bothzero = 0;

            int[] arraySeed = new int[] {-1, 1};
            int[] randomSource = new int[] {-1, 0, 0, 1};
            Random rand = new Random();

            foreach (var S in Enumerable.Repeat(arraySeed, n+1).CartesianProduct())
            {
                for (int i = 0; i < iters; i++)
                {
                    var F = Enumerable.Range(0, n).Select(_ => randomSource[rand.Next(randomSource.Length)]);
                    while (!F.Any(f => f != 0))
                    {
                        F = Enumerable.Range(0, n).Select(_ => randomSource[rand.Next(randomSource.Length)]);
                    }
                    if (Enumerable.Zip(F, S.Take(n), (f, s) => f * s).Sum() == 0)
                    {
                        firstzero++;
                        if (Enumerable.Zip(F, S.Skip(1), (f, s) => f * s).Sum() == 0)
                        {
                            bothzero++;
                        }
                    }
                }
            }

            Console.WriteLine("firstzero {0}", firstzero);
            Console.WriteLine("bothzero {0}", bothzero);
        }

        // itertools.product?
        // http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
        static IEnumerable<IEnumerable<T>> CartesianProduct<T>
            (this IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct =
              new[] { Enumerable.Empty<T>() };
            return sequences.Aggregate(
              emptyProduct,
              (accumulator, sequence) =>
                from accseq in accumulator
                from item in sequence
                select accseq.Concat(new[] { item }));
        }
    }
}

සමාන්තර C #:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConvolvingArrays
{
    static class Program
    {
        static void Main(string[] args)
        {
            int n=6;
            int iters = 1000;
            int firstzero = 0;
            int bothzero = 0;

            int[] arraySeed = new int[] {-1, 1};
            int[] randomSource = new int[] {-1, 0, 0, 1};

            ConcurrentBag<int[]> results = new ConcurrentBag<int[]>();

            // The next line iterates over arrays of length n+1 which contain only -1s and 1s
            Parallel.ForEach(Enumerable.Repeat(arraySeed, n + 1).CartesianProduct(), (S) =>
            {
                int fz = 0;
                int bz = 0;
                ThreadSafeRandom rand = new ThreadSafeRandom();
                for (int i = 0; i < iters; i++)
                {
                    var F = Enumerable.Range(0, n).Select(_ => randomSource[rand.Next(randomSource.Length)]);
                    while (!F.Any(f => f != 0))
                    {
                        F = Enumerable.Range(0, n).Select(_ => randomSource[rand.Next(randomSource.Length)]);
                    }
                    if (Enumerable.Zip(F, S.Take(n), (f, s) => f * s).Sum() == 0)
                    {
                        fz++;
                        if (Enumerable.Zip(F, S.Skip(1), (f, s) => f * s).Sum() == 0)
                        {
                            bz++;
                        }
                    }
                }

                results.Add(new int[] { fz, bz });
            });

            foreach (int[] res in results)
            {
                firstzero += res[0];
                bothzero += res[1];
            }

            Console.WriteLine("firstzero {0}", firstzero);
            Console.WriteLine("bothzero {0}", bothzero);
        }

        // itertools.product?
        // http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
        static IEnumerable<IEnumerable<T>> CartesianProduct<T>
            (this IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct =
              new[] { Enumerable.Empty<T>() };
            return sequences.Aggregate(
              emptyProduct,
              (accumulator, sequence) =>
                from accseq in accumulator
                from item in sequence
                select accseq.Concat(new[] { item }));
        }
    }

    // http://stackoverflow.com/a/11109361/1030702
    public class ThreadSafeRandom
    {
        private static readonly Random _global = new Random();
        [ThreadStatic]
        private static Random _local;

        public ThreadSafeRandom()
        {
            if (_local == null)
            {
                int seed;
                lock (_global)
                {
                    seed = _global.Next();
                }
                _local = new Random(seed);
            }
        }
        public int Next()
        {
            return _local.Next();
        }
        public int Next(int maxValue)
        {
            return _local.Next(maxValue);
        }
    }
}

පරීක්ෂණ ප්‍රතිදානය:

වින්ඩෝස් (.නෙට්)

C # වින්ඩෝස් වල වඩා වේගවත් ය. .NET මොනෝ වලට වඩා වේගවත් නිසා විය හැකිය.

පරිශීලක සහ සයිස් වේලාව වැඩ කරන බවක් නොපෙනේ ( git bashවේලාව සඳහා භාවිතා කරයි).

$ time /c/Python27/python.exe numpypython.py
firstzero 27413
bothzero 12073

real    0m5.907s
user    0m0.000s
sys     0m0.000s
$ time /c/Python27/python.exe plainpython.py
firstzero 26983
bothzero 12033

real    0m0.853s
user    0m0.000s
sys     0m0.000s
$ time ConvolvingArrays.exe
firstzero 28526
bothzero 6453

real    0m0.278s
user    0m0.000s
sys     0m0.000s
$ time ConvolvingArraysParallel.exe
firstzero 28857
bothzero 6485

real    0m0.135s
user    0m0.000s
sys     0m0.000s

ලිනක්ස් (මොනෝ)

bob@phoebe:~/convolvingarrays$ time python program.py
firstzero 27059
bothzero 12131

real    0m11.932s
user    0m11.912s
sys     0m0.012s
bob@phoebe:~/convolvingarrays$ mcs -optimize+ -debug- program.cs
bob@phoebe:~/convolvingarrays$ time mono program.exe
firstzero 28982
bothzero 6512

real    0m1.360s
user    0m1.532s
sys     0m0.872s
bob@phoebe:~/convolvingarrays$ mcs -optimize+ -debug- parallelprogram.cs
bob@phoebe:~/convolvingarrays$ time mono parallelprogram.exe
firstzero 28857
bothzero 6496

real    0m0.851s
user    0m2.708s
sys     0m3.028s

1
ඔබ කියන පරිදි කේතය නිවැරදි යැයි මම නොසිතමි. ප්‍රතිදානයන් නිවැරදි නැත.

@ ලෙම්බික් ඔව්. එය වැරදියි කියා යමෙකුට පැවසිය හැකි නම් මම එය අගය කරමි - මට එය හදුනාගත නොහැක (එය කළ යුතු දේ පිළිබඳ අවම අවබෝධයක් තිබීම පමණක් ප්‍රයෝජනවත් නොවේ).
බොබ්


@ ලෙම්බික් මම මේ සියල්ල ඉක්මවා ගොස් ඇත, මට කිව හැකි තාක් එය අනෙක් පයිතන් විසඳුමට සමාන විය යුතුය ... දැන් මම ඇත්තටම ව්‍යාකූල වී සිටිමි .
බොබ්

4

F # විසඳුම

සීඑල්ආර් කෝර් i7 4 (8) @ 3.4 Ghz හි x86 සමඟ සම්පාදනය කරන විට ධාවන කාලය 0.030s වේ

කේතය නිවැරදි දැයි මට අදහසක් නැත.

  • ක්‍රියාකාරී ප්‍රශස්තිකරණය (පේළිගත ගුණයකින්) -> 0.026s
  • කොන්සෝලය ව්‍යාපෘතිය හරහා ගොඩනැගීම -> 0.022s
  • ප්‍රේරක අරා උත්පාදනය සඳහා වඩා හොඳ ඇල්ගොරිතමයක් එක් කරන ලදි -> 0.018s
  • වින්ඩෝස් සඳහා මොනෝ -> 0.089s
  • ඇලිස්ටෙයාර්ගේ පයිතන් පිටපත ධාවනය කිරීම -> 0.259s
let inline ffoldi n f state =
    let mutable state = state
    for i = 0 to n - 1 do
        state <- f state i
    state

let product values n =
    let p = Array.length values
    Array.init (pown p n) (fun i ->
        (Array.zeroCreate n, i)
        |> ffoldi n (fun (result, i') j ->
            result.[j] <- values.[i' % p]
            result, i' / p
        )
        |> fst
    )

let convolute signals filter =
    let m = Array.length signals
    let n = Array.length filter
    let len = max m n - min m n + 1

    Array.init len (fun offset ->
        ffoldi n (fun acc i ->
            acc + filter.[i] * signals.[m - 1 - offset - i]
        ) 0
    )

let n = 6
let iters = 1000

let next =
    let arrays =
        product [|-1; 0; 0; 1|] n
        |> Array.filter (Array.forall ((=) 0) >> not)
    let rnd = System.Random()
    fun () -> arrays.[rnd.Next arrays.Length]

let signals = product [|-1; 1|] (n + 1)

let firstzero, bothzero =
    ffoldi signals.Length (fun (firstzero, bothzero) i ->
        let s = signals.[i]
        ffoldi iters (fun (first, both) _ ->
            let f = next()
            match convolute s f with
            | [|0; 0|] -> first + 1, both + 1
            | [|0; _|] -> first + 1, both
            | _ -> first, both
        ) (firstzero, bothzero)
    ) (0, 0)

printfn "firstzero %i" firstzero
printfn "bothzero %i" bothzero

3

රූබි

රූබි (2.1.0) 0.277s
රූබි (2.1.1) 0.281s
පයිතන් (ඇලිස්ටෙයාර් බක්ස්ටන්) 0.330s
පයිතන් (ඇලෙමී) 0.097s

n = 6
iters = 1000
first_zero = 0
both_zero = 0

choices = [-1, 0, 0, 1].repeated_permutation(n).select{|v| [0] != v.uniq}

def convolve(v1, v2)
  [0, 1].map do |i|
    r = 0
    6.times do |j|
      r += v1[i+j] * v2[j]
    end
    r
  end
end

[-1, 1].repeated_permutation(n+1) do |s|
  iters.times do
    f = choices.sample
    fs = convolve s, f
    if 0 == fs[0]
      first_zero += 1
      if 0 == fs[1]
        both_zero += 1
      end
    end
  end
end

puts 'firstzero %i' % first_zero
puts 'bothzero %i' % both_zero

3

නූල් PHP නොමැතිව සම්පූර්ණ නොවේ

6.6x වේගවත්

PHP v5.5.9 - තත්පර 1.223 0.646;

එදිරිව

පයිතන් v2.7.6 - තත්පර 8.072

<?php

$n = 6;
$iters = 1000;
$firstzero = 0;
$bothzero = 0;

$x=time();
$y=34353;
$z=57768;
$w=1564; //PRNG seeds

function myRand() {
    global $x;
    global $y;
    global $z;
    global $w;
    $t = $x ^ ($x << 11);
    $x = $y; $y = $z; $z = $w;
    return $w = $w ^ ($w >> 19) ^ $t ^ ($t >> 8);
}

function array_cartesian() {
    $_ = func_get_args();
    if (count($_) == 0)
        return array();
    $a = array_shift($_);
    if (count($_) == 0)
        $c = array(array());
    else
        $c = call_user_func_array(__FUNCTION__, $_);
    $r = array();
    foreach($a as $v)
        foreach($c as $p)
            $r[] = array_merge(array($v), $p);
    return $r;
}

function rand_array($a, $n)
{
    $r = array();
    for($i = 0; $i < $n; $i++)
        $r[] = $a[myRand()%count($a)];
    return $r;
}

function convolve($a, $b)
{
    // slows down
    /*if(count($a) < count($b))
        return convolve($b,$a);*/
    $result = array();
    $w = count($a) - count($b) + 1;
    for($i = 0; $i < $w; $i++){
        $r = 0;
        for($k = 0; $k < count($b); $k++)
            $r += $b[$k] * $a[$i + $k];
        $result[] = $r;
    }
    return $result;
}

$cross = call_user_func_array('array_cartesian',array_fill(0,$n+1,array(-1,1)));

foreach($cross as $S)
    for($i = 0; $i < $iters; $i++){
        while(true)
        {
            $F = rand_array(array(-1,0,0,1), $n);
            if(in_array(-1, $F) || in_array(1, $F))
                break;
        }
        $FS = convolve($S, $F);
        if(0==$FS[0]) $firstzero += 1;
        if(0==$FS[0] && 0==$FS[1]) $bothzero += 1;
    }

echo "firstzero $firstzero\n";
echo "bothzero $bothzero\n";
  • අභිරුචි සසම්භාවී උත්පාදක යන්ත්රයක් භාවිතා කර ඇත (සී පිළිතුරෙන් සොරකම් කරන ලදි), PHP එකක් උරා බොන අතර අංක නොගැලපේ
  • convolve ශ්‍රිතය වඩා වේගවත් වීමට ටිකක් සරල කර ඇත
  • අරාව-ශුන්‍ය-පමණක් සඳහා පරීක්ෂා කිරීම ද ඉතා ප්‍රශස්ත කර ඇත (බලන්න $Fසහ $FSපරීක්ෂා කිරීම).

නිමැවුම්:

$ time python num.py 
firstzero 27050
bothzero 11990

real    0m8.072s
user    0m8.037s
sys 0m0.024s
$ time php num.php
firstzero 27407
bothzero 12216

real    0m1.223s
user    0m1.210s
sys 0m0.012s

සංස්කරණය කරන්න. ස්ක්‍රිප්ට් හි දෙවන අනුවාදය සාධාරණ ලෙස ක්‍රියා කරයි 0.646 sec:

<?php

$n = 6;
$iters = 1000;
$firstzero = 0;
$bothzero = 0;

$x=time();
$y=34353;
$z=57768;
$w=1564; //PRNG seeds

function myRand() {
    global $x;
    global $y;
    global $z;
    global $w;
    $t = $x ^ ($x << 11);
    $x = $y; $y = $z; $z = $w;
    return $w = $w ^ ($w >> 19) ^ $t ^ ($t >> 8);
}

function array_cartesian() {
    $_ = func_get_args();
    if (count($_) == 0)
        return array();
    $a = array_shift($_);
    if (count($_) == 0)
        $c = array(array());
    else
        $c = call_user_func_array(__FUNCTION__, $_);
    $r = array();
    foreach($a as $v)
        foreach($c as $p)
            $r[] = array_merge(array($v), $p);
    return $r;
}

function convolve($a, $b)
{
    // slows down
    /*if(count($a) < count($b))
        return convolve($b,$a);*/
    $result = array();
    $w = count($a) - count($b) + 1;
    for($i = 0; $i < $w; $i++){
        $r = 0;
        for($k = 0; $k < count($b); $k++)
            $r += $b[$k] * $a[$i + $k];
        $result[] = $r;
    }
    return $result;
}

$cross = call_user_func_array('array_cartesian',array_fill(0,$n+1,array(-1,1)));

$choices = call_user_func_array('array_cartesian',array_fill(0,$n,array(-1,0,0,1)));

foreach($cross as $S)
    for($i = 0; $i < $iters; $i++){
        while(true)
        {
            $F = $choices[myRand()%count($choices)];
            if(in_array(-1, $F) || in_array(1, $F))
                break;
        }
        $FS = convolve($S, $F);
        if(0==$FS[0]){
            $firstzero += 1;
            if(0==$FS[1])
                $bothzero += 1;
        }
    }

echo "firstzero $firstzero\n";
echo "bothzero $bothzero\n";

2

Q, 0.296 seg

n:6; iter:1000  /parametrization (constants)
c:n#0           /auxiliar constant (sequence 0 0.. 0 (n))
A:B:();         /A and B accumulates results of inner product (firstresult, secondresult)

/S=sequence with all arrays of length n+1 with values -1 and 1
S:+(2**m)#/:{,/x#/:-1 1}'m:|n(2*)\1 

f:{do[iter; F:c; while[F~c; F:n?-1 0 0 1]; A,:+/F*-1_x; B,:+/F*1_x];} /hard work
f'S               /map(S,f)
N:~A; +/'(N;N&~B) / ~A is not A (or A=0) ->bitmap.  +/ is sum (population over a bitmap)
                  / +/'(N;N&~B) = count firstResult=0, count firstResult=0 and secondResult=0

Q යනු එකතුවට නැඹුරු භාෂාවකි (kx.com)

මුග්ධ Q පුපුරවා හැරීම සඳහා කේතය නැවත ලියා ඇත, නමුත් වෙනත් දක්ෂ ප්‍රශස්තිකරණයන් නොමැත

භාෂාවන් ස්ක්‍රිප්ටින් කිරීම මඟින් ක්‍රමලේඛක වේලාව මිස ක්‍රියාත්මක කිරීමේ වේලාව නොවේ

  • Q මෙම ගැටළුව සඳහා හොඳම මෙවලම නොවේ

පළමු කේතීකරණ උත්සාහය = ජයග්‍රාහකයෙකු නොව සාධාරණ කාලය (දළ වශයෙන් 30x වේගවත් කිරීම)

  • පරිවර්තකයන් අතර තරමක් තරඟකාරී
  • නැවතී වෙනත් ගැටලුවක් තෝරන්න

සටහන්.-

  • වැඩසටහන මඟින් පෙරනිමි බීජ භාවිතා කරයි (පුනරාවර්තනය කළ හැකි ක්‍රියාත්මක කිරීම්) අහඹු උත්පාදක භාවිතය සඳහා තවත් බීජයක් තෝරා ගැනීමට \S seed
  • ප්‍රති ult ලය අඟල් දෙකක වර්ගයක් ලෙස ලබා දී ඇත, එබැවින් දෙවන අගය 27421 12133i -> හි අවසාන i- උපසර්ගය ඇත (27241, 12133)
  • පරිවර්තක ආරම්භය ගණන් නොගන්නා කාලය. \t sentence එම වාක්‍යයෙන් ගතවන කාලය මැනීම

ඉතා රසවත් ස්තූතියි.

1

ජූලියා: 12.149 6.929 s

වේගය පිළිබඳ ඔවුන්ගේ ප්‍රකාශ තිබියදීත් , ආරම්භක JIT සම්පාදන කාලය අපව වළක්වයි!

පහත දැක්වෙන ජූලියා කේතය effectively ලදායී ලෙස මුල් පයිතන් කේතයේ සෘජු පරිවර්තනයක් බව (ප්‍රශස්තිකරණයන් සිදු නොකෙරේ) ඔබේ ක්‍රමලේඛන අත්දැකීම් වේගවත් භාෂාවකට පහසුවෙන් මාරු කළ හැකි බවට නිරූපණයක් ලෙස;)

require("Iterators")

n = 6
iters = 1000
firstzero = 0
bothzero = 0

for S in Iterators.product(fill([-1,1], n+1)...)
    for i = 1:iters
        F = [[-1 0 0 1][rand(1:4)] for _ = 1:n]
        while all((x) -> round(x,8) == 0, F)
            F = [[-1 0 0 1][rand(1:4)] for _ = 1:n]
        end
        FS = conv(F, [S...])
        if round(FS[1],8) == 0
            firstzero += 1
        end
        if all((x) -> round(x,8) == 0, FS)
            bothzero += 1
        end
    end
end

println("firstzero ", firstzero)
println("bothzero ", bothzero)

සංස්කරණය කරන්න

ධාවනය n = 8සඳහා තත්පර 32.935 ක් ගතවේ. මෙම ඇල්ගොරිතමය සංකීර්ණත්වය බව සලකා O(2^n)නම්, 4 * (12.149 - C) = (32.935 - C), කොහෙද Cසඳහා JIT සම්පාදන කාලය නියෝජනය නියත ය. සඳහා විසඳීම Cබව අපට දැකගත C = 5.2203සඳහා සැබෑ කියාත්මක කාලය බව යෝජනා, n = 66,929 ගේ වේ.


එවිට ජූලියා තමාටම ආවේ දැයි බැලීමට n සිට 8 දක්වා වැඩි කරන්නේ කෙසේද?

මෙය මෙහි බොහෝ කාර්ය සාධන ඉඟි නොසලකා හරියි: julia.readthedocs.org/en/latest/manual/performance-tips . සැලකිය යුතු ලෙස වඩා හොඳ වන අනෙක් ජූලියා ප්‍රවේශය ද බලන්න. ඉදිරිපත් කිරීම අගය කළත් :-)
ස්ටෙෆාන්කාර්පින්ස්කි

0

මලකඩ, 6.6 ms, 1950x වේගවත් කිරීම

ඇලිස්ටෙයාර් බක්ස්ටන්ගේ කේතය රස්ට් වෙත සෘජුවම පරිවර්තනය කිරීම . රේයාන් (නිර්භීත සහසම්බන්ධය!) සමඟ බහු හරයන් භාවිතා කිරීම ගැන මම සලකා බැලුවෙමි , නමුත් මෙය කාර්ය සාධනය වැඩි දියුණු නොකළේ, එය දැනටමත් ඉතා වේගවත් නිසා විය හැකිය.

extern crate itertools;
extern crate rand;
extern crate time;

use itertools::Itertools;
use rand::{prelude::*, prng::XorShiftRng};
use std::iter;
use time::precise_time_ns;

fn main() {
    let start = precise_time_ns();

    let n = 6;
    let iters = 1000;
    let mut first_zero = 0;
    let mut both_zero = 0;
    let choices_f: Vec<Vec<i8>> = iter::repeat([-1, 0, 0, 1].iter().cloned())
        .take(n)
        .multi_cartesian_product()
        .filter(|i| i.iter().any(|&x| x != 0))
        .collect();
    // xorshift RNG is faster than default algorithm designed for security
    // rather than performance.
    let mut rng = XorShiftRng::from_entropy(); 
    for s in iter::repeat(&[-1, 1]).take(n + 1).multi_cartesian_product() {
        for _ in 0..iters {
            let f = rng.choose(&choices_f).unwrap();
            if f.iter()
                .zip(&s[..s.len() - 1])
                .map(|(a, &b)| a * b)
                .sum::<i8>() == 0
            {
                first_zero += 1;
                if f.iter().zip(&s[1..]).map(|(a, &b)| a * b).sum::<i8>() == 0 {
                    both_zero += 1;
                }
            }
        }
    }
    println!("first_zero = {}\nboth_zero = {}", first_zero, both_zero);

    println!("runtime {} ns", precise_time_ns() - start);
}

මම බාහිර පරායත්තයන් භාවිතා කරන පරිදි Cargo.toml:

[package]
name = "how_slow_is_python"
version = "0.1.0"

[dependencies]
itertools = "0.7.8"
rand = "0.5.3"
time = "0.1.40"

වේග සංසන්දනය:

$ time python2 py.py
firstzero: 27478
bothzero: 12246
12.80user 0.02system 0:12.90elapsed 99%CPU (0avgtext+0avgdata 23328maxresident)k
0inputs+0outputs (0major+3544minor)pagefaults 0swaps
$ time target/release/how_slow_is_python
first_zero = 27359
both_zero = 12162
runtime 6625608 ns
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 2784maxresident)k
0inputs+0outputs (0major+189minor)pagefaults 0swaps

6625608 ns 6.6 ms පමණ වේ. මෙයින් අදහස් කරන්නේ 1950 ගුණයකින් වේගවත් වීමයි. මෙහි බොහෝ ප්‍රශස්තිකරණයන් කළ හැකි නමුත් මම යන්නේ කාර්ය සාධනයට වඩා කියවීමේ හැකියාව සඳහා ය. කළ හැකි එක් ප්‍රශස්තිකරණයක් වනුයේ තේරීම් ගබඩා කිරීම සඳහා දෛශික වෙනුවට අරා භාවිතා කිරීමයි n. XorShift හැර වෙනත් RNG භාවිතා කිරීමට ද හැකිය, Xorshift සුපුරුදු HC-128 CSPRNG ට වඩා වේගවත් වන අතර, එය PRNG ඇල්ගොරිතම වලට වඩා මන්දගාමී වේ.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.