C # 대 C-큰 성능 차이


94

C anc C #에서 유사한 코드간에 엄청난 성능 차이를 찾고 있습니다.

C 코드는 다음과 같습니다.

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

main()
{
    int i;
    double root;

    clock_t start = clock();
    for (i = 0 ; i <= 100000000; i++){
        root = sqrt(i);
    }
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);   

}

그리고 C # (콘솔 앱)은 다음과 같습니다.

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

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;
            double root;
            for (int i = 0; i <= 100000000; i++)
            {
                root = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds/1000));
        }
    }
}

위 코드를 사용하면 C #이 0.328125 초 (릴리스 버전)에 완료되고 C가 실행되는 데 11.14 초가 걸립니다.

c는 mingw를 사용하여 실행 가능한 Windows로 컴파일됩니다.

저는 항상 C / C ++가 더 빠르거나 적어도 C # .net과 비슷하다는 가정하에있었습니다. C가 30 배 이상 느리게 실행되는 원인은 정확히 무엇입니까?

편집 : C # 최적화 프로그램이 사용되지 않았기 때문에 루트를 제거하는 것처럼 보입니다. 루트 할당을 루트 + =로 변경하고 끝에 합계를 인쇄했습니다. 또한 최대 속도로 설정된 / O2 플래그와 함께 cl.exe를 사용하여 C를 컴파일했습니다.

결과는 다음과 같습니다. C의 경우 3.75 초 C #의 경우 2.61 초

C는 여전히 더 오래 걸리지 만 이것은 허용됩니다


18
DateTime 대신 StopWatch를 사용하는 것이 좋습니다.
Alex Fort

2
어떤 컴파일러 플래그? 둘 다 최적화를 사용하여 컴파일 되었습니까?
jalf

2
C ++ 컴파일러와 함께 -ffast-math를 사용하면 어떨까요?
Dan McClain

10
정말 흥미로운 질문입니다!
Robert S.

4
아마도 C sqrt 함수는 C #에서 이만큼 좋지 않을 수 있습니다. 그러면 C에서는 문제가되지 않지만 라이브러리가 첨부되어 있습니다. 수학 함수없이 몇 가지 계산을 시도하십시오.
klew

답변:


61

'root'를 사용하지 않았으므로 컴파일러가 메서드를 최적화하기 위해 호출을 제거했을 수 있습니다.

제곱근 값을 누산기에 누적하고 메서드의 끝에서 인쇄하고 무슨 일이 일어나는지 볼 수 있습니다.

편집 : 아래 Jalf의 답변 참조


1
약간의 실험은 이것이 사실이 아님을 시사합니다. 루프에 대한 코드가 생성되지만 런타임이이를 건너 뛸 수있을만큼 똑똑 할 수도 있습니다. 축적도, C #을 여전히 C의 바지를 친다
다나

3
문제가 다른쪽에있는 것 같습니다. C #은 모든 경우에 합리적으로 작동합니다. 그의 C 코드는 최적화없이 컴파일 된 것 같습니다
jalf

2
많은 분들이 여기서 요점을 놓치고 있습니다. 저는 C #이 C / C ++보다 성능이 뛰어나고 항상 전문가 수준의 최적화를 사용하는 것이 반박되는 유사한 사례를 많이 읽었습니다. 프로그래머의 99 %는 코드를 C # 코드보다 약간 빠르게 실행하기 위해 이러한 최적화 기술을 사용할 지식이 없습니다. c / c ++의 사용 사례가 축소되고 있습니다.

167

디버그 빌드를 비교해야합니다. 방금 C 코드를 컴파일하고

Time elapsed: 0.000000

최적화를 활성화하지 않으면 수행하는 벤치마킹은 완전히 가치가 없습니다. (최적화를 활성화하면 루프가 최적화됩니다. 따라서 벤치마킹 코드에도 결함이 있습니다. 일반적으로 결과 또는 유사한 결과를 합산하고 마지막에 출력하여 루프를 실행하도록 강제해야합니다.)

당신이 측정하는 것은 기본적으로 "어떤 컴파일러가 가장 많은 디버깅 오버 헤드를 삽입하는지"인 것 같습니다. 그리고 답은 C입니다. 그러나 그것은 어떤 프로그램이 가장 빠른지 알려주지 않습니다. 속도를 원할 때 최적화를 활성화하기 때문입니다.

그건 그렇고, 언어가 서로 "빠르다"는 개념을 버리면 장기적으로 많은 두통을 피할 수 있습니다. C #은 영어보다 속도가 빠릅니다.

C 언어에는 최적화되지 않은 순진한 컴파일러에서도 효율적인 특정 사항이 있으며 모든 것을 최적화하기 위해 컴파일러에 크게 의존하는 다른 것들이 있습니다. 물론 C #이나 다른 언어도 마찬가지입니다.

실행 속도는 다음에 의해 결정됩니다.

  • 실행중인 플랫폼 (OS, 하드웨어, 시스템에서 실행되는 기타 소프트웨어)
  • 컴파일러
  • 당신의 소스 코드

좋은 C # 컴파일러는 효율적인 코드를 생성합니다. 잘못된 C 컴파일러는 느린 코드를 생성합니다. C # 코드를 생성 한 다음 C # 컴파일러를 통해 실행할 수있는 C 컴파일러는 어떻습니까? 얼마나 빨리 실행 될까요? 언어에는 속도가 없습니다. 당신의 코드는 그렇습니다.



18
좋은 대답이지만 적어도 유 추적으로는 언어 속도에 대해서는 동의하지 않습니다. Welsch는 장모음의 빈도가 높기 때문에 대부분의 언어보다 느린 언어라는 것이 밝혀졌습니다. 또한 사람들은 말이 더 빠를수록 단어 (및 단어 목록)를 더 잘 기억합니다. web.missouri.edu/~cowann/docs/articles/before%201993/... en.wikipedia.org/wiki/Vowel_length en.wikipedia.org/wiki/Welsh_language
exceptionerror

1
그것은 당신이 Welsch에서 말하는 것에 달려 있지 않습니까? 모든 것이 더 느릴 것 같지는 않습니다 .
jalf 2009-06-12

5
++ 안녕하세요 여러분, 여기에서 횡보하지 마십시오. 같은 프로그램이 다른 언어보다 한 언어에서 더 빠르게 실행된다면 다른 어셈블리 코드가 생성되기 때문입니다. 이 특정 예에서 99 % 이상의 시간이 플로팅 i, 및 으로 이동 sqrt하므로 이것이 측정되고 있습니다.
Mike Dunlavey

116

간략하게 설명하겠습니다. 이미 답변으로 표시되어 있습니다. C #은 잘 정의 된 부동 소수점 모델을 갖는 큰 장점이 있습니다. 이는 x86 및 x64 프로세서에서 설정된 FPU 및 SSE 명령어의 기본 작동 모드와 일치합니다. 우연이 없습니다. JITter는 Math.Sqrt ()를 몇 가지 인라인 명령어로 컴파일합니다.

네이티브 C / C ++는 수년간의 이전 버전과의 호환성을 갖추고 있습니다. / fp : precise, / fp : fast 및 / fp : strict 컴파일 옵션이 가장 잘 보입니다. 따라서 sqrt ()를 구현하는 CRT 함수를 호출하고 선택한 부동 소수점 옵션을 확인하여 결과를 조정해야합니다. 느립니다.


66
이것은 C ++ 프로그래머들 사이에서 이상한 확신입니다. 그들은 C #에 의해 생성 된 기계어 코드가 네이티브 컴파일러에 의해 생성 된 기계어 코드와 어떻게 든 다르다고 생각하는 것 같습니다. 종류는 하나뿐입니다. 사용하는 gcc 컴파일러 스위치 나 작성하는 인라인 어셈블리에 관계없이 FSQRT 명령어는 여전히 하나뿐입니다. 네이티브 언어가 생성했기 때문에 항상 빠르지는 않습니다. CPU는 신경 쓰지 않습니다.
Hans Passant

16
이것이 ngen.exe로 사전 설정하면 해결되는 것입니다. 우리는 자바가 아닌 C #에 대해 이야기하고 있습니다.
Hans Passant 2012 년

20
@ user877329-정말? 와.
Andras Zoltan 2012

7
아니요, x64 지터는 SSE를 사용합니다. Math.Sqrt ()는 sqrtsd 기계어 코드 명령어로 변환됩니다.
Hans Passant

6
기술적으로 언어 간의 차이는 아니지만 .net JITter는 일반적인 C / C ++ 컴파일러에 비해 다소 제한적인 최적화를 수행합니다. 가장 큰 한계 중 하나는 SIMD 지원이 부족하여 코드가 약 4 배 더 느려진다는 것입니다. 많은 내장 함수를 노출하지 않는 것도 큰 악의적 일 수 있지만, 그것은 당신이하는 일에 따라 많이 달라집니다.
CodesInChaos 2013 년

57

저는 C ++ 및 C # 개발자입니다. .NET 프레임 워크의 첫 번째 베타 이후 C # 응용 프로그램을 개발했으며 C ++ 응용 프로그램 개발에 20 년 이상의 경험을 가지고 있습니다. 첫째, C # 코드는 C ++ 응용 프로그램보다 빠르지는 않지만 관리 코드, 작동 방식, 상호 운영 계층, 메모리 관리 내부, 동적 유형 시스템 및 가비지 수집기에 대해 긴 논의를 거치지 않을 것입니다. 그럼에도 불구하고 여기에 나열된 벤치 마크가 모두 잘못된 결과를 생성한다고 말하면서 계속하겠습니다.

설명해 드리겠습니다. 가장 먼저 고려해야 할 것은 C # 용 JIT 컴파일러 (.NET Framework 4)입니다. 이제 JIT는 다양한 최적화 알고리즘 (Visual Studio와 함께 제공되는 기본 C ++ 최적화 프로그램보다 더 공격적인 경향이 있음)을 사용하여 CPU 용 네이티브 코드를 생성하고 .NET JIT 컴파일러에서 사용하는 명령 집합은 실제 CPU를 더 가깝게 반영합니다. 따라서 기계 코드에서 특정 대체를 수행하여 클럭 사이클을 줄이고 CPU 파이프 라인 캐시의 적중률을 개선하고 분기 예측과 관련된 명령 재정렬 및 ​​개선과 같은 추가 하이퍼 스레딩 최적화를 생성 할 수 있습니다.

이것이 의미하는 바는 RELEASE 빌드 (DEBUG 빌드가 아님)에 대해 올바른 매개 변수를 사용하여 C ++ 애플리케이션을 컴파일하지 않으면 C ++ 애플리케이션이 해당 C # 또는 .NET 기반 애플리케이션보다 느리게 수행 될 수 있다는 것입니다. C ++ 애플리케이션에서 프로젝트 속성을 지정할 때 "전체 최적화"및 "빠른 코드 선호"를 활성화해야합니다. 64 비트 머신이있는 경우 x64를 대상 플랫폼으로 생성하도록 지정해야합니다. 그렇지 않으면 코드가 변환 하위 계층 (WOW64)을 통해 실행되어 성능이 크게 저하됩니다.

컴파일러에서 올바른 최적화를 수행하면 C ++ 애플리케이션의 경우 .72 초, C # 애플리케이션의 경우 1.16 초 (둘 다 릴리스 빌드에서)가됩니다. C # 애플리케이션은 매우 기본적이며 힙이 아닌 스택의 루프에서 사용되는 메모리를 할당하기 때문에 실제로 개체, 무거운 계산 및 더 큰 데이터 세트와 관련된 실제 애플리케이션보다 훨씬 더 나은 성능을 발휘합니다. 따라서 제공된 수치는 C # 및 .NET 프레임 워크에 편향된 낙관적 인 수치입니다. 이러한 편견에도 불구하고 C ++ 애플리케이션은 동등한 C # 애플리케이션보다 절반이 조금 넘는 시간에 완료됩니다. 필자가 사용한 Microsoft C ++ 컴파일러에는 올바른 파이프 라인 및 하이퍼 스레딩 최적화가 없었습니다 (WinDBG를 사용하여 어셈블리 지침보기).

이제 Intel 컴파일러 (AMD / Intel 프로세서에서 고성능 응용 프로그램을 생성하는 업계 비밀)를 사용하면 동일한 코드가 C ++ 실행 파일의 경우 .54 초, Microsoft Visual Studio 2010을 사용하는 경우 .72 초만에 실행됩니다. 결국 최종 결과는 C ++의 경우 .54 초, C #의 경우 1.16 초입니다. 따라서 .NET JIT 컴파일러에 의해 생성되는 코드는 C ++ 실행 파일보다 214 % 더 오래 걸립니다. .54 초에 소요 된 대부분의 시간은 루프 자체가 아닌 시스템에서 시간을 얻는 데있었습니다!

통계에서 누락 된 것은 타이밍에 포함되지 않은 시작 및 정리 시간입니다. C # 애플리케이션은 C ++ 애플리케이션보다 시작 및 종료에 더 많은 시간을 소비하는 경향이 있습니다. 그 이유는 복잡하고 메모리 할당과 가비지를 최적화하기 위해 프로그램의 시작 (결과적으로 끝)에서 많은 작업을 수행하는 .NET 런타임 코드 유효성 검사 루틴 및 메모리 관리 하위 시스템과 관련이 있습니다. 수집기.

C ++ 및 .NET IL의 성능을 측정 할 때 어셈블리 코드를 살펴보고 모든 계산이 있는지 확인하는 것이 중요합니다. 내가 찾은 것은 C #에 추가 코드를 넣지 않고 위의 예제에있는 대부분의 코드가 실제로 바이너리에서 제거되었다는 것입니다. 인텔 C ++ 컴파일러와 함께 제공되는 최적화 프로그램과 같은보다 공격적인 최적화 프로그램을 사용할 때 C ++에서도 마찬가지입니다. 위에서 제공 한 결과는 100 % 정확하고 어셈블리 수준에서 검증되었습니다.

많은 초보자들이 기술을 이해하지 않고 Microsoft 마케팅 선전을 듣고 C #이 C ++보다 빠르다는 잘못된 주장을하는 인터넷의 많은 포럼의 주요 문제입니다. 이론적으로 C #은 JIT 컴파일러가 CPU 용 코드를 최적화 할 수 있기 때문에 C ++보다 빠르다는 것입니다. 이 이론의 문제점은 성능을 저하시키는 .NET 프레임 워크에 존재하는 많은 배관이 있다는 것입니다. C ++ 애플리케이션에 존재하지 않는 배관. 또한 숙련 된 개발자는 주어진 플랫폼에 사용할 올바른 컴파일러를 알고 애플리케이션을 컴파일 할 때 적절한 플래그를 사용할 것입니다. Linux 또는 오픈 소스 플랫폼에서는 소스를 배포하고 적절한 최적화를 사용하여 코드를 컴파일하는 설치 스크립트를 만들 수 있으므로 이는 문제가되지 않습니다. Windows 또는 폐쇄 된 소스 플랫폼에서는 각각 특정 최적화가 적용된 여러 실행 파일을 배포해야합니다. 배포 될 Windows 바이너리는 msi 설치 프로그램이 감지 한 CPU를 기반으로합니다 (사용자 지정 작업 사용).


22
1. 마이크로 소프트는 C #이 속도의 약 90 %, 개발 속도가 빠르며 (따라서 조정하는 데 더 많은 시간이 소요되며) 메모리 및 형식 안전성으로 인해 버그가 없다고 주장하지 않았습니다. 모두 사실입니다 (C ++에서 20 년, C #에서 10 년). 2. 대부분의 경우 시작 성능은 의미가 없습니다. 3. LLVM과 같은 더 빠른 C # 컴파일러도 있습니다 (따라서 Intel을 출시하는 것은 Apple이 아닙니다)
ben

13
시작 성능은 의미가 없습니다. 대부분의 엔터프라이즈 웹 기반 응용 프로그램에서 매우 중요하므로 Microsoft가 .NET 4.0에 미리로드 (자동 시작) 할 웹 페이지를 도입했습니다. 응용 프로그램 풀이 가끔씩 재활용되는 경우 각 페이지가 처음로드 될 때 복잡한 페이지에 상당한 지연이 추가되고 브라우저에서 시간 초과가 발생합니다.
Richard

8
Microsoft는 이전 마케팅 자료에서 .NET의 성능이 더 빠르다고 주장했습니다. 그들은 또한 가비지 수집기가 성능에 거의 또는 전혀 영향을 미치지 않는다는 다양한 주장을했습니다. 이러한 주장 중 일부는 이전 버전의 다양한 서적 (ASP.NET 및 .NET)으로 만들었습니다. Microsoft는 C # 응용 프로그램이 C ++ 응용 프로그램보다 빠르다고 구체적으로 말하지는 않지만 "Just-In-Time Means Run-It-Fast"( msdn.microsoft.com/) 와 같은 일반적인 의견과 마케팅 슬로건을 쓸 수 있습니다. en-us / library / ms973894.aspx ).
Richard

71
-1,이 폭언은 명백한 "C # 코드는 C ++ 응용 프로그램보다 절대 빠르지 않을 것입니다"와 같은 부정확하고 오해의 소지가있는 진술로 가득 차 있습니다.
BCoates

32
-1. Rico Mariani 대 Raymond Chen의 C # 대 C 성능 전투 : blogs.msdn.com/b/ricom/archive/2005/05/16/418051.aspx를 읽어야 합니다. 간단히 말해서, Microsoft에서 가장 똑똑한 사람 중 한 명이 단순한 C # 버전보다 C 버전을 더 빠르게 만들기 위해 많은 최적화 작업이 필요했습니다.
Rolf Bjarne Kvinge

10

내 첫 번째 추측은 루트를 사용하지 않기 때문에 컴파일러 최적화입니다. 할당 한 다음 반복해서 덮어 씁니다.

편집 : 젠장, 9 초로 이길!


2
나는 당신이 맞다고 말합니다. 실제 변수는 덮어 쓰여지고 그 이후로는 사용되지 않습니다. csc는 대부분의 경우 전체 루프를 무시하고 C ++ 컴파일러는 아마도 그것을 남겨 둘 것입니다.보다 정확한 테스트는 결과를 축적 한 다음 그 결과를 마지막에 출력하는 것입니다. 또한 시드 값을 하드 코딩하지 말고 사용자 정의 상태로 두어야합니다. 이것은 C # 컴파일러에게 물건을 남길 여지를주지 않습니다.

7

루프가 최적화되고 있는지 확인하려면 코드를

root += Math.Sqrt(i);

C 코드에서 비슷하게 ans를 입력 한 다음 루프 외부에 루트 값을 인쇄합니다.


6

아마도 C # 컴파일러는 루트를 어디에도 사용하지 않는다는 것을 알아 차렸 기 때문에 전체 for 루프를 건너 뜁니다. :)

그렇지 않을 수도 있지만 원인이 무엇이든 컴파일러 구현에 따라 다릅니다. 최적화 및 릴리스 모드를 사용하여 Microsoft 컴파일러 (cl.exe, win32 sdk의 일부로 사용 가능)로 C 프로그램을 컴파일 해보십시오. 다른 컴파일러보다 성능이 향상 될 것입니다.

편집 : Math.Sqrt ()에 부작용이 없다는 것을 알아야하기 때문에 컴파일러가 for 루프를 최적화 할 수 있다고 생각하지 않습니다.


2
아마도 그것을 알고있을 것입니다.

2
@Neil, @jeff : 동의합니다. 꽤 쉽게 알 수 있습니다. 구현에 따라 Math.Sqrt ()에 대한 정적 분석은 그다지 어렵지 않을 수 있지만 구체적으로 수행되는 최적화가 무엇인지 확실하지 않습니다.
John Feminella

5

시간이 다르더라도. "경과 시간"이 유효하지 않을 수 있습니다. 두 프로그램이 정확히 동일한 조건에서 실행되도록 보장 할 수있는 경우에만 유효한 것입니다.

승리를 시도해야 할 수도 있습니다. $ / usr / bin / time my_cprog; / usr / bin / time my_csprog와 동일


1
왜 이것이 반대 투표입니까? 인터럽트 및 컨텍스트 스위치가 성능에 영향을 미치지 않는다고 가정하는 사람이 있습니까? 누구든지 TLB 미스, 페이지 스와핑 등에 대한 가정을 할 수 있습니까?
Tom

5

나는 (귀하의 코드를 기반으로) C와 C #에서 두 가지 더 비교 가능한 테스트를 모았습니다. 이 둘은 인덱싱을 위해 모듈러스 연산자를 사용하여 더 작은 배열을 작성합니다 (약간의 오버 헤드가 추가되지만 성능을 [조잡한 수준에서] 비교하려고합니다).

C 코드 :

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

void main()
{
    int count = (int)1e8;
    int subcount = 1000;
    double* roots = (double*)malloc(sizeof(double) * subcount);
    clock_t start = clock();
    for (int i = 0 ; i < count; i++)
    {
        roots[i % subcount] = sqrt((double)i);
    }
    clock_t end = clock();
    double length = ((double)end - start) / CLOCKS_PER_SEC;
    printf("Time elapsed: %f\n", length);
}

C #에서 :

using System;

namespace CsPerfTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = (int)1e8;
            int subcount = 1000;
            double[] roots = new double[subcount];
            DateTime startTime = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                roots[i % subcount] = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds / 1000));
        }
    }
}

이러한 테스트는 배열이 상당히 작지만 (과도한 메모리를 사용하고 싶지 않음) 배열에 데이터를 씁니다 (따라서 .NET 런타임이 sqrt 작업을 컬링하도록 허용해서는 안 됨). 릴리스 구성에서 컴파일하고 VS를 통해 시작하는 대신 콘솔 창에서 실행했습니다.

내 컴퓨터에서 C # 프로그램은 6.2 초에서 6.9 초 사이이며 C 버전은 6.9 초에서 7.1 초 사이입니다.


5

제곱근 루틴을 단계별로 수행하는 것을 포함하여 어셈블리 수준에서 코드를 한 단계 만 수행하면 질문에 대한 답을 얻을 수 있습니다.

교육받은 추측이 필요 없습니다.


나는이 작업을 수행하는 방법을 알고 싶습니다
조쉬 Stodola에게

IDE 또는 디버거에 따라 다릅니다. pgm의 시작 부분에서 중단하십시오. 분해 창을 표시하고 단일 스테핑을 시작합니다. GDB를 사용하는 경우 한 번에 하나의 명령을 단계별로 실행하는 명령이 있습니다.
Mike Dunlavey

이것은 좋은 팁입니다. 이것은 실제로 아래에서 일어나는 일을 훨씬 더 많이 이해하는 데 도움이됩니다. 인라인 및 테일 호출과 같은 JIT 최적화도 표시됩니까?
gjvdkamp

참고로 : 나를 위해 이것은 fadd 및 fsqrt를 사용하는 VC ++를 보여 주었지만 C #은 내가 이해하는 바와 같이 Cvtsi2sd 및 sqrtsd를 사용했으며 SSE2 명령이며 지원되는 경우 상당히 빠릅니다.
danio

2

여기서 문제가 될 수있는 또 다른 요인은 C 컴파일러가 대상 프로세서 제품군에 대한 일반 네이티브 코드로 컴파일되는 반면 C # 코드를 컴파일 할 때 생성 된 MSIL은 JIT 컴파일되어 완료 한 프로세서를 대상으로합니다. 가능한 최적화. 따라서 C #에서 생성 된 네이티브 코드는 C보다 훨씬 빠를 수 있습니다.


이론적으로는 그렇습니다. 실제로는 실제로 측정 가능한 차이를 만들지 않습니다. 운이 좋으면 1 ~ 2 퍼센트 정도.
jalf

또는- '일반'프로세서에 허용 된 목록에없는 확장을 사용하는 특정 유형의 코드가있는 경우. SSE 풍미와 같은 것. 프로세서 타겟을 더 높게 설정하여 어떤 차이가 있는지 확인하십시오.
gbjbaanb

1

이것은 언어 자체와는 아무런 관련이없는 것 같으며, 오히려 제곱근 함수의 다른 구현과 관련이있는 것 같습니다.


나는 다른 sqrt 구현이 그렇게 많은 차이를 유발할 것이라고 의심합니다.
Alex Fort

특히 C #에서도 대부분의 수학 함수는 여전히 성능에 중요한 것으로 간주되고 그 자체로 구현됩니다.
Matthew Olenik

fsqrt는 IA-32 프로세서 명령어이므로 요즘에는 언어 구현과 관련이 없습니다.
확실하지 않음

디버거를 사용하여 MSVC의 sqrt 함수에 들어갑니다. fsqrt 명령을 실행하는 것 이상을 수행합니다.
bk1e

1

실제로 여러분, 루프가 최적화되지 않고 있습니다. John의 코드를 컴파일하고 결과 .exe를 조사했습니다. 루프의 핵심은 다음과 같습니다.

 IL_0005:  stloc.0
 IL_0006:  ldc.i4.0
 IL_0007:  stloc.1
 IL_0008:  br.s       IL_0016
 IL_000a:  ldloc.1
 IL_000b:  conv.r8
 IL_000c:  call       float64 [mscorlib]System.Math::Sqrt(float64)
 IL_0011:  pop
 IL_0012:  ldloc.1
 IL_0013:  ldc.i4.1
 IL_0014:  add
 IL_0015:  stloc.1
 IL_0016:  ldloc.1
 IL_0017:  ldc.i4     0x5f5e100
 IL_001c:  ble.s      IL_000a

런타임이 루프가 아무 일도하지 않고 건너 뛰는 것을 깨달을만큼 똑똑하지 않다면?

편집 : C #을 다음과 같이 변경합니다.

 static void Main(string[] args)
 {
      DateTime startTime = DateTime.Now;
      double root = 0.0;
      for (int i = 0; i <= 100000000; i++)
      {
           root += Math.Sqrt(i);
      }
      System.Console.WriteLine(root);
      TimeSpan runTime = DateTime.Now - startTime;
      Console.WriteLine("Time elapsed: " +
          Convert.ToString(runTime.TotalMilliseconds / 1000));
 }

내 컴퓨터에서 경과 된 시간이 0.047에서 2.17로 이동합니다. 그러나 그것은 단지 1 억 덧셈 연산자를 추가하는 오버 헤드일까요?


3
IL을 보면 최적화에 대해 많이 알려주지 않습니다. C # 컴파일러가 상수 폴딩 및 데드 코드 제거와 같은 작업을 수행하더라도 IL이 대신로드시 나머지 작업을 수행하기 때문입니다.
Daniel Earwicker

그게 사실이라고 생각했던 것입니다. 강제로 작동하더라도 C 버전보다 9 초 더 빠릅니다. (I 예상하지 않았을 모든에서)
다나
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.