[CS] Lecture5

Minsol·2024년 10월 14일
0

🖥️CS

목록 보기
4/12

Chapter2

Data race와 Atomic Operation의 원리

Data race (데이터 경쟁)

  • 공유된 위치에 두 개의 동시 접근이 발생하고, 그 중 적어도 하나의 접근이 쓰기 작업을 포함할 때

Atomic Operations (원자적 연산)


  • 메모리 위치 주소에서 하나의 ISA 명령어로 수행됨
      1. 이전의 값을 읽음
      1. 새 값을 계산함
      1. 새 값을 해당 위치에 씀 => 이 순서대로!!
  • 하드웨어는 원자적 연산이 완료될때까지 다른 thread가 해당 위치에 접근하지못하게 함
    • 해당 위치에 접근하려는 다른 thread는 대기열에서 차례를 기다림
    • 모든 thread는 원자적 연산을 직렬로(serially) 수행

Translation and Startup


C프로그램이 컴파일되고 실행파일로 생성된 후 메모리에서 실행되는 과정!

  1. C Program
    사람이 읽을 수 있는 고급언어(HLL)

    (compiler): 어셈블리 수준의 언어 프로그램으로 변환하는 과정 수행
  2. Assembly language program

    (Assembler): 어셈블리 언어 프로그램을 기계어 모듈(==오브젝트 파일)로 변환
  3. Object: Machine language module, Object: Library routine(machine language)

    (Linker): 기계어로 작성된 오브젝트 파일과 라이브러리나 다른 모듈을 결합하여 실행 파일을 완성시킴
  4. Executable: Machine Language program
    실행파일 -> 기계어 프로그램

    (Loader): 최종적으로 완성된 실행 파일을 메모리로 로드하는 역할
  5. Memory
  • 많은 컴파일러는 직접적으로 오브젝트 모듈을 생성함
  • Static linking(정적 링크): 모든 필요한 코드가 하나의 실행 파일에 결합되어 외부 라이브러리 없이 독립적으로 실행될 수 있도록 함

Array(배열) vs Pointer(포인터)

배열

  • 배열 인덱싱은 각 접근마다 인덱스를 요소 크기와 곱해야함
  • 배열의 기본 주소에 더함
    뜻: 배열의 각 인덱스에 접근할 때는 배열의 기본 주소(base address)에 인덱스 요소 크기를 더해 메모리 위치를 계산, ex. arr[2]에 접근하려면 배열의 기본 주소에 2 4(4바이트는 int 크기)를 더해 실제 메모리 위치를 계산

포인터

  • 메모리 주소에 직접 대응하여 인덱싱의 복잡함을 피할 수 있음

배열과 포인터의 비교

    1. 배열 -> 포인터로 바꾸면, 곱셈이 shift로 바귀어 강도가 감소함!
    1. 배열은 루프 내부에서 shift가 필요함
    • 증가하는 i에 대한 인덱스 계산의 일부
    • cf. 포인터를 증가하는 것과 비교
    1. 컴파일러의 효과 == 포인터를 수동으로 사용하는 것의 효과
    • 귀납 변수(induction variable)를 제거함 (반복문의 i++를 제거)
    • 프로그램을 더 명확하고 안전하게 만듦
      (즉, 컴파일할때 배열로 작성되어 있어도 다 포인터로 바꾼다는 뜻)

Fallacies and Pitfalls

<instruction의 중요성 알기>

  • 강력한 명령어 == 더 높은 성능
    • 적은 명령어가 필요함 (메모리를 적게 쓰기 위해)
    • 복잡한 명령어는 구현하기 어려움
      • 단순한 명령어를 포함한 모든 명령어를 느리게 만들 수 있음
    • 컴파일러는 단순한 명령어로부터 빠른 코드를 작성하는 데 능숙함
  • 높은 성능을 위해 어셈블리 코드를 사용
    - 현대 컴파일러는 최신 프로세서를 더 잘 처리함
    • 코드 라인이 많아질수록 오류가 증가하고 생산성이 감소함

  • 명령어 집합은 변하지 않음 => 하위 호환성
    - 시간이 지남에 따라 명령어가 더 추가되기는 하지만(확장), 새 시스템이나 소프트웨어가 이전 버전에서 사용된 명령어 집합을 그대로 유지함으로써 기존과 호환될 수 있도록 함

Chapter3: Arithmetic for Computer(컴퓨터의 산술 연산)

정수 연산

정수 덧셈(Integer Addition)

  • 오버플로우: 결과가 범위를 벗어날 경우 발생
    • 양수 + 음수 => 오버플로우 발생 x
    • 양수 + 양수 => 계산 결과에서 부호(sign) 비트가 1인경우 오버플로우 발생한 것
      • 32비트 정수에서 최대값 + 10 => 음수로 넘어감
    • 음수 + 음수 => 계산 결과에서 부호(sign) 비트가 0인경우 오버플로우 발생한 것
      • 32비트 정수의 거의 최솟값 + -10 => 양수로 넘어감

정수 뺄셈(Integer Subtraction)

  • 정수 뺄셈: 두 번째 피연산자(operand)의 부호를 반전시켜서 더하는 방식으로 수행
    • ex. 7 - 6 = 7 + (-6)
      • 2의 보수로 -6을 구함
  • 오버플로우: 결과가 범위를 벗어날 경우 발생
    • 양수 - 양수, 음수 - 음수 => 오버플로우 발생 x
    • 음수 - 양수 => 부호(sign) 비트가 0인경우 오버플로우 발생한 것
    • 양수 - 음수 => 부호(sign) 비트가 1인경우 오버플로우 발생한 것

+) 2의 보수 구하는 방법
1. 이진수의 모든 비트를 반전시킴 -> 1의 보수
2. 1을 더함

  • ex. 6의 2의 보수
      1. 6을 4bit 2진수로 표현하면, 0110
      1. 1의 보수 => 1001
      1. 1 더하기 => 1010

정수 곱셈 (Integer Multiplication)

  • 긴 곱셈(long-multiplication) 방법을 사용하여 수행
    • 곱셈 과정은 10진수(deximal) 곱셈과 동일한 방식으로 수행
      - 각 비트에 대해 곱셈을 수행 -> 부분 곱에 더해줌
      • 이진수 => A와 B의 곱셈은 AND 연산으로 수행 (둘다 1일때만 1)
        - 곱셈의 결과 길이 == 피연산자의 길이 합 (4자리 + 4자리 = 8자리, 결과도 8자리)

🌟Floating Point

  • 정수가 아닌 숫자를 표현하기 위한 방법 (매우 작은수, 매우 큰 수를 모두 표현할 수 있음!)
  • 과학적 표기법과 유사함
    • 10진수 기본 골자 => ±0.00 × 10ⁿ를 꼭 지켜야함!
  • 2진수 기본 골자 => ±1.xxxxxxx × 2ⁿ(여기서 n은 4개)
  • c언어에서는 float와 double로 사용됨

부동소수점 표준(Floating Point Standard)

  • IEEE Std 754-1985에 의해 정의됨
  • 다양한 부동소수점 표현의 차이로 인해 개발된 표준으로, 과학 계산용 코드의 이식성 문제 해결 위해 만들어짐!
  • 현재는 전 세계적으로 채택됨!
  • 두 가지 표현방식
      1. Single Precision (32-bit, 단정밀도)
      1. Double Precision (64-bit, 배정밀도)

IEEE Floating-Point Format

  • S(부호): Sign bit
    • 0: 양수, 1: 음수
  • 정규화된 가수(normalize significand): 1.0 ≤ |significand| < 2.0
    • 항상 1이 선행하는 비트이므로, 이를 명시적으로 표현할 필요x (== 숨겨진 bit)
    • 가수는 분수(fraction)으로 표현되고 "1."은 연산시 복원됨
  • Exponent(지수): 초과 표현방식으로, 실제 지수 값 + Bias로 표현됨
    • Single precision(단정밀도): Bias = 127
    • Double precision(배정밀도): Bias = 1023

Example


profile
👀

0개의 댓글