강승현입니다
    • 홈
    • 태그
    • 방명록

    카테고리

    • 전체 글 (118) N
      • 후기 (38)
        • 경험 (15)
        • SSAFY (9)
        • 코딩테스트 (3)
        • 넥스터즈 (6)
        • 회고 (5)
      • Degrees (2)
      • Tech (33) N
      • OnlineJudge (45)
    Tech

    Python3 나누기연산(/)과 시프트연산(>>)의 속도 차이를 알아보자

    CODe_byCODe_·2021. 2. 15. 15:34

    목차


      결론

      시프트연산이 더 빠릅니다. (미미하게)

      시프트 연산은 int형이 32bits이므로 사용하는데 제한이 있습니다. 물론 언어별로 사용할 수 있는 방법이 상이한 것으로 알고 있습니다.

       

      필요한 상황에 따라, 본인 스타일에 따라 적절히 사용하시면 되겠습니다.


      Python 디스어셈블러

      테스트 코드

      내부적으로 어떻게 다른지 간단하게 살펴보겠습니다.

      코드는 위의 소스코드를 사용했으며, 나누기 연산을 호출할 때와 시프트를 호출할 때 디스어셈블러로 살펴보았습니다.

       

      나누기 연산
      시프트 연산

      차이점은 BINARY_TRUE_DIVIDE와 BINARY_RSHIFT를 호출 하는 것입니다.

      내부적인 동작을 살펴보려 했으나 자세한 내용이 설명된 DOC이 없어서 생략하겠습니다.

      결론적으로 파이썬3(3.6~3.8)에선 별도의 최적화 과정은 없었습니다.


      C++ 디스어셈블러

      이번엔 C++ 10.2 버전을 살펴보겠습니다.

      int div(int num) {
          return num/2;
      }
      
      int shift(int num){
          return num>>1;
      }

       

       

      Python3와 마찬가지로 나누기와 시프트 연산의 내부 구조가 다른 것을 볼 수 있습니다.

      Python3에서는 BINARY_TRUE_DIVIDE와 BINARY_RSHIFT만 보였고 doc을 찾아봐도 자세한 정보는 알 수 없었으나

      역시 C++은 적나라하게 보여주는군요.

       

      나누기 함수에서 7번째 줄 shr이 보이시나요?

      이 어셈블리어는 SHIFT를 호출하는 것 입니다. 시프트연산과 동일한 과정을 수행하지만 결국 추가적인 명령을 수행하는 것을 볼 수 있습니다.

       

      shr : 부호가 없는 연산 (오른쪽으로 시프트)

      sar : 부호가 있는 연산 (오른쪽으로 시프트)

       

      만약, 부호가 없다면(unsigned int) 시프트와 나누기 연산은 내부적으로 완전히 동일한 기능을 수행합니다.

      위 예시 코드에서 결론은 shift 연산과 동일한 과정이지만, 추가적인 명령을 수행한다고 볼 수 있습니다.


      VSCode에서 Python3 테스트

       이제 나누기 연산과 시프트 연산의 시간 차이를 눈으로 확인해 보겠습니다.

       

      import time
      count = 100000000
      avg = [0]*100
      for i in range(100):
          value = 10000000
          start = time.time_ns()
          for _ in range(count):
              value/=2
          div = time.time_ns()-start
      
          value = 10000000
          start = time.time_ns()
          for _ in range(count):
              value>>=1
          shift = time.time_ns()-start
          avg[i] = div-shift
          
      print(avg)
      print(sum(avg)/100)

       

      코드는 위의 코드를 사용했으며, 1억번 연산을 100회 실행하여 평균 시간을 도출했습니다.

       

      [1505195300, 1662018500, 1410215200, 1602844400, 1389873100, 1436921000, 1482024500, 1421643800, 1354637300, 1509224200, 1440094900, 1442721500, 1432760600, 1374821700, 296575800, 1982800000, 1450574300, 1410184900, 1436426200, 1460545200, 1412427000, 1453337300, 1358454000, 1466627500, 1385027400, 1459110100, 1450241500, 1420757300, 1435558400, 1524951000, 1418618000, 1185107900, 1856469600, 1400374000, 1337578800, 1335638000, 1465059800, 1405475800, 1481497500, 1300591100, 1603461500, 1400138500, 1310093800, 1477803400, 1490994800, 1425624100, 1493999400, 1472720300, 1517472600, 1461114200, 1309039100, 1506191100, 1431269100, 1431624200, 1247834000, 1452928000, 1491006700, 1454307300, 1387261200, 1374231400, 1391278800, 1301174100, 1385268300, 1437294600, 1344928000, 1470457000, 1402268200, 1416270600, 1391254300, 1507361000, 1376247500, 1435292300, 1362242200, 1434293800, 1394266100, 1449307000, 1419271900, 1423294500, 1409284500, 1392245000, 1428302500, 1233730000, 1340334400, 1442561800, 1452408600, 1404517100, 1288058600, 1521229700, 1492831800, 1516045200, 1558808200, 1476988700, 1402288700, 1432834800, 1332659300, 1367718000, 1601572400, 1583981900, 1478395000, 1445039100]


      1427377246.0 ns

       

      약 1.4초의 차이가 났습니다. (컴퓨터 사양마다 상이할 수 있습니다)

       

      물론 알고리즘 문제를 풀면서 1억번의 연산을 하는 문제가 많은 비중을 차지하는 것도 아니고, 1억이 적은 횟수도 아니기 때문에 나누기 연산을 시프트 연산으로 바꾼다고 문제가 통과될 수준은 아닌 것 같습니다.

      반응형
      저작자표시 비영리 변경금지 (새창열림)
      'Tech' 카테고리의 다른 글
      • [Spring] HikariCP Dead lock 벗어나기
      • [Java] Error와 Exception에 대해
      • 몸소 겪었던 Python과 PyPy의 차이(메모리,속도)
      • [JAVA 기초] 1. JAVA의 특징
      CODe_
      CODe_
      개발과 관련된 다양한 정보를 몰입감있게 전달합니다.
      최신 글

      티스토리툴바