2013-07-07 1 views
3

이 줄리아 식 배열을 만들지 않도록 할 수있는 방법이 있나요 :줄리아 식으로 배열을 만들지 않도록 할 방법이 있습니까?

max((filter(n -> string(n) == reverse(string(n)), [x*y for x = 1:N, y = 1:N]))) 

을하고이 파이썬 발전기 표현과 유사한 동작합니다

max(x*y for x in range(N+1) for y in range(x, N+1) if str(x*y) == str(x*y)[::-1]) 

줄리아 버전은 파이썬으로 인해 다음 2.3 배 느립니다 배열 할당과 N * N 반복 대 파이썬의 N * N/2.

편집

줄리아 몇 구현으로 비트를 연주 후, 내가있어 가장 빠른 루프 스타일의 버전은 다음과 같습니다

function f(N) # 320ms for N=1000 Julia 0.2.0 i686-w64-mingw32 
    nMax = NaN 
    for x = 1:N, y = x:N 
     n = x*y 
     s = string(n) 
     s == reverse(s) || continue 
     nMax < n && (nMax = n) 
    end 
    nMax 
end 

하지만 개선 된 기능 버전은 멀리 뒤에되지 않습니다 (2 배 더 큰 도메인을 고려하면 14 % 만 느리거나 상당히 빠름) :

function e(N) # 366ms for N=1000 Julia 0.2.0 i686-w64-mingw32 
    isPalindrome(n) = string(n) == reverse(string(n)) 
    max(filter(isPalindrome, [x*y for x = 1:N, y = 1:N])) 
end 

예기치 않은 perf 이 페이지의 상단에 오리지널 버전과 비교하여 isPalindrome 기능을 정의하여 분위기를 개선하십시오.

+1

멋진 작품. 여기에'filter (isPalindrome, ...)'을 쓸 수 있습니다. – StefanKarpinski

+0

@StefanKarpinski 감사합니다. 지금은 훨씬 좋네요. –

답변

11

우리는 다른 코 루틴에 최대를 계산하는 동안 하나의 코 루틴의 값 f(x)의 각을 생성하기위한 속기로 구문

max(f(x) for x in itr) 

허용에 대해 이야기했다 . 이것은 기본적으로 다음과 같이 뭔가를 속기 것이다 : 그러나

max(@task for x in itr; produce(f(x)); end) 

주, 명시 적으로 작업을 만들고이 구문이 이미 작동하는지, 그것은 다소 덜 꽤 위보다 있지만.문제는 다음과 같이 표현 될 수있다 위의 가상 생산 구문

max(@task for x=1:N, y=x:N 
    string(x*y) == reverse(string(x*y)) && produce(x*y) 
end) 

, 그것이 이런 식으로 줄일 수있는이에

max(x*y if string(x*y) == reverse(string(x*y) for x=1:N, y=x:N) 

나는 기능적인 스타일의 팬이에요 동안, 경우에 나는 아마 for 루프를 사용합니다 :

m = 0 
for x = 1:N, y = x:N 
    n = x*y 
    string(n) == reverse(string(n)) || continue 
    m < n && (m = n) 
end  

는 개인적으로, 나는 읽을 더 힘들어 버전을 찾을 수없는 그것은 확실히 줄리아에 매우 빠르게 될 것입니다. 일반적으로 기능적 스타일은 편리하고 예쁘다.하지만 성능에 중점을두면 명시적인 for 루프는 친구 다. 그럼에도 불구하고 John의 최대/필터/제품 버전이 작동하는지 확인해야합니다. for 루프 버전은 Harlan이 제안한 루프 순서를 바꾸고 첫 번째 회문에서 빠져 나오는 것과 같은 다른 최적화를 쉽게 추가 할 수 있도록합니다. 또한 문자열이 실제로 생성되고 비교되는 것보다 주어진 숫자에서 회귀 식 (palindrome)인지 확인하는 더 빠른 방법이 있습니다.

는 "줄리아 유연한 발전기, 지능형리스트를 받고"의 일반적인 문제에 관해서는, 언어는 이미 다음 기능/수행/시작에 따라

  1. 일반적인 고성능 반복 프로토콜이있다.
  2. 대부분의 언어보다 훨씬 강력한 다차원 배열 내포물입니다. 이 시점에서 누락 된 유일한 기능은 if 가드인데, 이는 다차원 적 이해와 상호 작용하고 잠재적으로 동적으로 결과 배열을 성장시킬 필요가 있기 때문에 복잡합니다.
  3. 다른 패턴 중에서도 생산자 - 소비자 패턴을 허용하는 코 루틴 (일명 작업).

파이썬은 if 가드를 가지고 있지만 거의만큼 이해 성능에 대해 걱정하지 않습니다 - 우리가 줄리아의 함축에 해당 기능을 추가려고하는 경우에, 우리의 방식으로 그것을 할거야 모두 빠르고 다차원 배열과 잘 상호 작용하므로 지연이 발생합니다.

:

업데이트 : 예를 들어, 당신은이 작업을 수행 할 수 있도록max 기능이 이제 (sum+에 그대로 maximummax이다) maximum이라고하며 발전기 구문 및/또는 필터는, 마스터 작업

julia> @time maximum(100x - x^2 for x = 1:100 if x % 3 == 0) 
    0.059185 seconds (31.16 k allocations: 1.307 MB) 
2499 

0.5가 나오면이 답변을보다 철저히 업데이트하겠습니다. 언급 한 바와 같이

+1

줄리아에서 metaprogramming 된 모든 장점을 사용하여 'x = 1 인 경우 문자열 (x * y) == 역순 (문자열 (x * y) 인 경우 x * y : N, y = x : N' 위에서 쓴 루프에 직접 연결하고 코 루틴 호출 오버 헤드와 글루 로직을 피하십시오. 가능합니까? –

+0

기능적 스타일을 사용하는 또 다른 이유는 정확성 보장입니다. 명령형 코드를 작성할 때 코드가 올바른지 확인해야합니다 당신이 요즘 바쁜 사람이라는 것을 알고 있지만, 당신이 쓴 루프는 두 가지 문제가 있습니다 : 초기 값은 NaN이고 max = n은 nMax = max (n, nMax)이어야합니다. 'OTAH, 위의 한 줄의 선언적 (기능적) 버전은 이러한 문제로부터 자유 롭다. 나는 질질 거리고있는 것을 의미하지는 않는다. 단지 설명의 의미가있다. 선언적'max'는 최대, 필수 최대 구현은 입증 될 때까지 올바르지 않다. 그렇지 않은 경우 –

+0

최상의 루프 버전과 수정 된 기능 버전의 벤치 마크를 추가했습니다. 16 % 느립니다. –

2

나는 그렇게 생각하지 않는다. Julia array comprehensions에는 현재 필터가 없습니다. this issue의 토론을 참조하십시오.

더 빠른 계산을 원한다면이 특별한 경우에는 중첩 된 for 루프를 제안 할 것입니다.

(가 ... 더 빨리 당신은 빨리 당신이 등 제대로 연습 문제로 남겨되는 작업을 수행하는 방법을 알아내는. 성공 무언가를 발견하면 중지 N 시작하여 거꾸로 계산 곳에 접근 할 수 있음)

+0

그 스레드를 보았습니다. 줄리아에서 융통성있는 발전기 또는 목록 이해력을 얻기위한 희망이 있습니까? 그들은 Matlab 패러다임에서 너무 멀었습니까? 알고리즘을 변경하는 한, 내 질문의 범위를 넘어선 다른 운동입니다. –

5

여기에 두 가지 질문이 섞여 있습니다. (1) 목록 이해력 중간 이해도 (해당 대답은 현재 아니오)를 필터링 할 수 있으며 (2) 배열을 할당하지 않는 생성기를 사용할 수 있습니까? 대답은 부분적으로 그렇습니다). 생성기는 Iterators 패키지에 의해 제공되지만 Iterators 패키지는 현재 filter과 잘 작동하지 않는 것 같습니다. 원칙적으로, 아래의 코드는 작동합니다 :

max((x, y) -> x * y, 
    filter((x, y) -> string(x * y) == reverse(string(x * y)), 
      product(1:N, 1:N))) 
+0

'product' 기능을 사용할 수 있습니까? 어디에서 찾을 수 있습니까? –

1

이 지금은 다른 사람들이 댓글 수있는 더 나은 방법이 확신

isPalindrome(n::String) = n == reverse(n) 
fun(N::Int) = maximum(x*y for x in 1:N for y in x:N if isPalindrome(string(x*y))) 

(줄리아 0.5.0 사용) 할 수 있습니다. 시간 (예열 후) :

julia> @time fun(1000); 
    0.082785 seconds (2.03 M allocations: 108.109 MB, 27.35% gc time)