Floating-Point Binary Representation

부동 소수점 이진 표현

  •  부동 소수점 십진수는 세 가지 구성 요소를 포함함
    • 부호 (Sign), 가수 (Significand 또는 Mantissa), 지수 (Exponent)
    • 예: -1.23154 x 10^5에서 부호는 음수, 가수는 1.23154, 지수는 5

IEEE Binary Floating-Point Representation

IEEE 이진 부동 소수점 표현

 

  •  x86 프로세서는 IEEE 754-1985 표준에 지정된 세 가지 형식을 사용 
    • 단정밀도 (Single Precision)
      • 32비트: 부호 1비트, 지수 8비트, 가수 23비트. approximate 정규화 범위: 2^-126 ~ 2^127. "short real"이라고도 함.
    • Double Precision
      • 64비트 : 부호 1비트, 지수 11비트, 가수 52비트. 2^-1023 ~ 2^1023. "long real"이라고도 한다
    • Double Extended Precision
      • 80비트 : 부호 1비트, 지수 16비트, 가수 63비트, "extended real"이라고도 한다.

Fraction Segment는 유효숫자 소수 부분을 나타낸다. 즉, 정수 부분을 제외한 소수를 나타낸다.

  • ex) 유효 숫자 1.2345에서 0.2345에 해당하는 부분

 

  • 부호 (Sign)
    • 1: 음수, 0: 양수 (0 포함)
  • 가수 (Significand 또는 Mantissa)
    • 가수는 소수점의 왼쪽과 오른쪽에 있는 십진수 자릿수로 구성됨
    • 예: 11.1011 = (1 x 2^1) + (1 x 2^0) + (1 x 2^-1) + (0 x 2^-2) + (1 x 2^-3) + (1 x 2^-4)

  • 유효숫자의 정확도
    • 단순한 floating-point format이 5bit의 유효숫자를 갖는다고 하면, 이진수 1.1111과 10.000 사이에 속하는 숫자를 표현할 방법이 없다. 정밀도 이슈가 있다
    • IEEE Single-precision(단밀정도) format의 24비트 유효숫자는 25개 비트 이상의 이진값을 표현하지 못한다
      • 원래 23 bit로 나타내고, 정규화를 하면 유효숫자 첫 비트가 1이라고 암묵적으로 가정하여 저장하기 때문에 24비트 유효숫자인 것이다.
      • 지수부에 바이어스 127를 더한 값인 0과 255를 사용하지 않는 이유는 첫 비트가 0이 아닌 경우를 처리하기 위함임
  • 지수 (Exponent)
    • 단정밀도 지수는 127의 바이어스가 더해져 8비트 부호 없는 정수로 저장됨
      • 예: 이진 값 1.101 x 2^5의 바이어스된 지수는 132 (5+127)
    • 바이어스된 지수는 항상 양수이며, 1과 254 사이임
      • 실제 지수 범위는 -126 부터 127까지 이다.
      • 가장 작은 가능한 지수의 역수가 오버플로를 일으키지 않도록 범위가 선택되었습니다.

질문) 단정밀도에서 왜 정규화 범위가 2^-126~ 2^127인가요?

1. 지수의 비트 수

단정밀도 형식에서 지수는 8비트로 표현됩니다. 8비트로 표현할 수 있는 이진수의 범위는 0부터 255까지입니다.

2. 지수의 바이어스

IEEE 754 표준에서는 지수를 바이어스(bias)를 사용하여 저장합니다. (바이어스를 더하는 이유는 지수가 음수일수도, 양수일 수도 있어서 지수를 양수로 표현하기 위함이다) 단정밀도 형식의 경우 바이어스 값은 127입니다. 즉, 실제 지수를 저장할 때는 이 값에 127을 더하여 저장합니다. 이를 통해 지수의 저장 범위는 다음과 같습니다:

  • 실제 지수가 −12일 때 저장되는 값은 1 (127 + (-126))
  • 실제 지수가 127일 때 저장되는 값은 254 (127 + 127)

0과 255는 특별한 값을 나타내는 데 사용되기 때문에 일반적인 지수 범위에서는 제외됩니다.

그래서 0과 255에서 127을 빼면 -127~128이고, 경계를 제외하면 -126~127이다.

Normalized Binary Floating-Point Numbers

정규화된 이진 부동 소수점 숫자

  • 부동 소수점 숫자는 가수의 정밀도를 극대화하기 위해 정규화된 형태로 저장됨
    • 이진 소수점을 단일 '1'이 이진 소수점 왼쪽에 나타날 때까지 이동시켜 정규화 가능 (1.XXX...b 형태로 만들어준다)
    • 지수는 이진점이 왼쪽으로 이동하는 위치의 수(양의 지수) 또는 오른쪽으로 이동하는 위치의 수(음의 지수)를 나타냅니다.

  • 비정규화된 값들
    • 정규화 작업을 되돌리는 것은 이진 부동 소수점 수를 비정규화하는 것입니다.
    • 지수가 0이 될 때까지 이진점을 이동시킵니다.
      • 지수가 양의 n인 경우, 이진점을 오른쪽으로 n칸 이동시킵니다.
      • 지수가 음의 n인 경우, 이진점을 왼쪽으로 n칸 이동시킵니다.

Creating the IEEE Representation

IEEE 표현 생성

  • 실수 인코딩
    • 부호 비트, 지수, 가수 필드를 정규화하고 인코딩한 후 부호 비트를 먼저, 지수 비트를 다음, 가수의 소수 부분을 마지막에 배치함
    • 예: 1.101 x 2^0는 다음과 같이 표현됨:
      • 부호 비트: 0
      • 지수: 01111111 (0+127)
      • 가수: 10100000000000000000000
      • 모든 정규화된 가수는 이진점 왼쪽에 1을 가지므로 비트를 명시적으로 인코딩할 필요가 없습니다.

정규화된 (Normalized) 및 비정규화된 (Denormalized)

  • 정규화된 유한 숫자
    • 0과 무한대 사이의 정규화된 실수로 인코딩할 수 있는 모든 비영(非零) 유한 값
  • 모든 finite nonzero 부동 소수점 숫자가 정규화될 수 있는 것은 아님
    • FPU가 지수 범위의 제한 때문에 이진 소수점을 정규화된 위치로 이동할 수 없을 때 발생
    • ex) 1.010111000....1111 X 2^(-129)
      • 지수가 single-precision 으로 저장하기에 너무 작다
      • Underflow 예외 상황이 발생하며, 지수가 유효한 범위에 도달할 때까지 이진점을 한 비트씩 왼쪽으로 이동시키면서 숫자를 점진적으로 비정규화합니다
        • Underflow : 소수가 너무 작아져서 표현 가능한 범위를 넘는 것

이 예에서는 이진 소수점의 이동으로 인해 가수에서 일부 정밀도 손실이 발생했습니다.

  • 양의 무한대 및 음의 무한대
    • 양의 무한대 (+∞)는 최대 양의 실수를 나타냄
    • 음의 무한대 (-∞)는 최대 음의 실수를 나타냄
    • 무한대를 다른 값과 비교 가능
      • -∞는 +∞보다 작음
      • -∞는 모든 유한 수보다 작음
      • +∞는 모든 유한 수보다 큼
  • 무한대는 부동 소수점 Overflow 조건을 나타낼 수 있습니다.
    • 계산 결과가 정규화될 수 없는 이유는 그 지수가 표현 가능한 지수 비트 수로는 너무 커서 표현할 수 없기 때문입니다.
  • NaNs (Not a Number)
    • 유효한 실수를 나타내지 않는 비트 패턴
    • x86에는 두 종류의 NaN이 포함됨
      • Quiet NaN (QNaN): 예외 없이 대부분의 산술 연산을 통해 전파될 수 있음
      • Signaling NaN (SNaN): 부동 소수점 잘못된 연산 예외를 생성하는 데 사용될 수 있음
    • 위의 NaNs 내용은 수업시간에 PASS 하고 지나간 부분

0을 2가지 방법으로 나타낼 수 있다 정도만 알고 넘어가자

Converting Decimal Fractions to Binary Reals

  • 십진 소수를 이진 실수로 변환
    • 십진 소수가 다음 형식으로 표현될 때 쉽게 변환 가능:
      • 1/2 + 1/4 + 1/8 + …
    • 그러나 많은 실수는 유한한 수의 이진 숫자로 표현될 수 없음
      • 이러한 분수는 분모가 2의 거듭제곱인 분수들의 합으로만 근사할 수 있습니다

Binary Long Division 사용

  • 분자와 분모를 이진수로 변환한 후 long division 수행
  • 예: 십진 0.5는 분수 5/10으로 표현됨
    • 십진 5는 이진 0101, 십진 10은 이진 1010
    • binary log division 수행, 몫은 0.1 binary

 

  • 0.2를 이진수로 나타내기
    • 몫의 비트 순서가 반복됩니다 (0011...)
    • 정확한 몫을 찾을 수 없으며 0.2는 유한한 비트 수로 표현될 수 없습니다.
    • 단정밀도로 인코딩된 가수는 00110011001100110011001입니다.
    • 이렇듯 2진수로 완전하게 표현이 불가능한 숫자들이 존재하기 때문에, precision이 존재한다.

 

  • Single-Precision Values to Decimal 변환
    1. MSB(최상위 비트)가 1이면 숫자는 음수이고, 그렇지 않으면 양수입니다.
    2. 다음 8비트는 지수(exponent)를 나타냅니다.
      • 01111111 (decimal 127)을 뺍니다. 이를 통해 unbiased exponent를 계산합니다.
      • Unbiased exponent를 10진수로 변환합니다.
    3. 다음 23비트는 유효숫자(significand)를 나타냅니다.
      • “1.”을 표기하고, 그 뒤에 유효숫자 비트를 붙입니다.
      • 끝의 0은 무시해도 됩니다.
      • 유효숫자, 부호(sign), 지수를 사용하여 부동 소수점 이진수를 만듭니다.
    4. Step 3에서 생성된 이진수를 비정규화(denormalize)합니다.
      • 지수 값만큼 이진 소수점을 이동시킵니다.
      • 지수가 양수면 오른쪽으로, 음수면 왼쪽으로 이동합니다.
    5. 왼쪽에서 오른쪽으로 가며 가중치 위치 표기법(weighted positional notation)을 사용하여 부동 소수점 이진수가 나타내는 10진수 합계를 만듭니다.
  • ex) IEEE(0 10000010 01011000....) to Decimal(10.75)

Floating-Point Unit

History of FPU in x86

  • Intel 8086 프로세서는 정수 연산만 처리하도록 설계되었습니다.
    • 이는 부동 소수점 계산을 사용하는 그래픽 및 계산 집중 소프트웨어에 문제가 되었습니다.
  • Intel은 8087이라는 별도의 부동 소수점 보조 프로세서 칩을 판매했으며, 각 프로세서 세대마다 업그레이드했습니다.
  • Intel486의 등장으로 부동 소수점 하드웨어가 메인 CPU에 통합되었고 FPU로 불렸습니다.

1. FPU Register Stack

  • FPU는 general-purpose register(EAX, EBX 등)를 사용하지 않습니다.
  • 대신, 레지스터 스택(register stack)이라는 고유한 레지스터 집합을 가지고 있습니다.
    • 메모리에서 레지스터 스택으로 값을 로드하고 계산을 수행하며 스택에 값을 저장합니다.

 

우리가 수업시간에 쓰는 실제 메모리 주소 그림으로 이해하려면 거꾸로 뒤집어서 생각하자

 

  • FPU Data Registers
    • FPU에는 R0에서 R7까지 명명된 8개의 개별 80비트 Data Registers가 있습니다.
      • 이들은 함께 register stack이라 불립니다.
    • 3비트 필드인 FPU status에 있는 TOP 필드는 FPU 레지스터 스택의 상단에 있는 레지스터의 인덱스(register number)를 나타냅니다
      • 이 스택 위치는 부동 소수점 명령어 작성 시 ST(0) 또는 간단히 ST로도 알려져 있습니다.
    • Push(로드) 및 Pop(저장)
      • Push 연산은 TOP 레지스터를 1 감소시킵니다.
        • 피연산자가 ST(0)으로 복사됩니다.
        • Push 전에 TOP이 0이면 R7로 래핑됩니다.
      • Pop은 ST(0)의 데이터를 피연산자로 복사하고 TOP을 1 증가시킵니다.
        • Pop 전에 TOP이 7이면 R0으로 래핑됩니다.
    • 부동 소수점 예외
      • load 연산이 레지스터 스택의 기존 데이터를 덮어쓰려고 할 때 발생합니다.
  • 레지스터에 있는 부동 소수점 값은 IEEE 10바이트 확장 실수 형식을 사용합니다.

Special-Purpose Registers

 

이 부분은  교수님이 대충 보고 넘어가자고 하심

  • FPU에는 여섯 개의 특수 목적 레지스터가 있습니다.
    • Opcode register
      • 마지막으로 실행된 비제어 명령의 오피코드를 저장합니다.
    • Control register
      • FPU가 계산을 수행할 때 사용하는 정밀도와 반올림 방법을 제어합니다.
      • 개별 부동 소수점 예외를 숨기기 위해 사용할 수도 있습니다.
      • floating point는 기본적으로 반올림 하는데, 올림이나 내림 설정을 하는 레지스터
    • Status register
      • 스택 포인터의 최상위, 조건 코드 및 예외 경고를 포함합니다.
    • Tag register
      • FPU 데이터 레지스터 스택의 각 레지스터 내용을 나타냅니다.
      • 유효한 숫자, 0 또는 특별한 값(NaN, 무한대, 비정상 형식 또는 지원되지 않는 형식)을 포함하는지 여부를 나타내기 위해 레지스터 당 2비트를 사용합니다.
    • Last instruction pointer register
      • 마지막으로 실행된 비제어 명령어를 가리킵니다.
    • Last data (operand) pointer register
      • 마지막으로 실행된 명령어에 의해 사용된 데이터 피연산자를 가리킵니다.

2. Rounding

  • FPU는 부동 소수점 계산에서 무한히 정확한 결과를 생성하려고 시도합니다.
    • 그러나 많은 경우 대상 피연산자가 계산된 결과를 정확하게 나타낼 수 없어 불가능합니다.
      • 예) 특정 저장 형식에서 세 개의 소수 비트(예: 1.011)만 허용한다고 가정
        • 계산된 결과가 +1.0111(10진수 1.4375)을 생성했다고 가정합니다.
        • .0001을 더해 숫자를 다음 높은 값으로 반올림하거나 .0001을 빼서 아래로 반올림할 수 있습니다.
          • 1.0111 --> 1.100 (rounding)
          • 1.0111 --> 1.011 (truncate)

아래 내용은 간단히 보고 넘어가자. 중요한 내용 아님

  • FPU는 네 가지 반올림 방법을 제공합니다.
    • 가장 가까운 짝수로 반올림 (Round to nearest even)
      • 반올림된 결과는 무한히 정확한 결과에 가장 가깝습니다.
      • 두 값이 동일하게 가까운 경우 결과는 짝수 값이 됩니다 (LSB = 0).
    • 음의 무한대로 반올림 (Round down toward -∞)
      • 반올림된 결과는 무한히 정확한 결과보다 작거나 같습니다.
    • 양의 무한대로 반올림 (Round up toward +∞)
      • 반올림된 결과는 무한히 정확한 결과보다 크거나 같습니다.
    • 0으로 반올림 (Round toward zero, truncation)
      • 반올림된 결과의 절대 값은 무한히 정확한 결과보다 작거나 같습니다.

FPU Control Word

이 부분도 수업시간에 PASS함

  • FPU 제어 워드는 두 비트를 포함하며, RC (Rounding Control) 필드를 가집니다.
    • 사용할 반올림 방법을 지정합니다.
      • 00 binary: 가장 가까운 짝수로 반올림 (기본값)
      • 01 binary: 음의 무한대로 반올림
      • 10 binary: 양의 무한대로 반올림
      • 11 binary: 0으로 반올림 (절단)
    • 예제: +1.0111 반올림
      • Method: Round to nearest even, Precise Result: 1.0111, Rounded: 1.100
      • Method: Round down toward -∞, Precise Result: 1.0111, Rounded: 1.011
      • Method: Round up toward +∞, Precise Result: 1.0111, Rounded: 1.100
      • Method: Round toward zero, Precise Result: 1.0111, Rounded: 1.011
    • 예제: -1.0111 반올림
      • Method: Round to nearest (even), Precise Result: -1.0111, Rounded: -1.100
      • Method: Round down toward -∞, Precise Result: -1.0111, Rounded: -1.100
      • Method: Round toward +∞, Precise Result: -1.0111, Rounded: -1.011
      • Method: Round toward zero, Precise Result: -1.0111, Rounded: -1.011

3. Floating-Point Exceptions

  • FPU는 여섯 가지 예외 조건을 인식하고 탐지합니다.
    • Invalid operation (#I), Divide by zero (#Z), Denormalized operand (#D)
      • 이들은 어떤 산술 연산이 발생하기 전에 탐지됩니다.
    • Numeric overflow (#O), Numeric underflow (#U), Inexact precision (#P)
      • 이들은 연산이 발생한 후 탐지됩니다.

 

아래 부분은 이런 내용이 있구나 정도로만 확인하고 넘어가자

  • 각 예외 유형에는 해당 플래그 비트와 마스크 비트가 있습니다.
    • 부동 소수점 예외가 감지되면 프로세서는 일치하는 플래그 비트를 설정합니다.
    • 프로세서가 예외를 플래그로 설정하면 두 가지 동작 코스가 있습니다.
      • 해당 마스크 비트가 설정된 경우
        • 프로세서는 예외를 자동으로 처리하고 프로그램을 계속 실행합니다.
      • 해당 마스크 비트가 설정되지 않은 경우
        • 프로세서는 소프트웨어 예외 처리기를 호출합니다.
      • bit masking으로 동작을 세팅한다

4. Floating-Point Instruction Set

Floating-point instruction notation

  • 부동 소수점 명령어 이름은 F로 시작합니다.

Memory operand type indicator (명령어 니모닉의 두 번째 문자)

  • B : BCD (Binary Coded Decimal) 피연산자
    • BCD는 안 다뤘으니 PASS하고 넘어가자
  • I : binary integer 피연산자
    • floating point 수를 다루는데 integer 피연산자를 사용할 수 있다.
  • None: 실수 형식
    • 예) FBLD는 BCD 숫자에서 작동하고, FILD는 정수에서 작동하며, FLD는 실수에서 작동합니다.

Operands

  • 부동 소수점 명령어는 0개, 1개 또는 2개의 피연산자를 가질 수 있습니다.
  • 피연산자가 두 개 있는 경우, 하나는 부동 소수점 레지스터여야 합니다.
  • immediate operands는 없습니다.
    • 그러나 0.0, π, log₂10와 같은 특정 정의된 상수는 스택에 로드될 수 있습니다.
    • 스택으로 push 해서 사용할 수는 있다.
  • General-purpose registers는 피연산자가 될 수 없습니다.
  • 메모리 간의 연산은 허용되지 않습니다.
  • 정수 피연산자는 메모리에서 FPU로 로드되어야 합니다 (CPU 레지스터에서 로드되지 않음).
    • 자동으로 부동 소수점 형식으로 변환됩니다.
    • 메모리에서 정수 표현 방식을 floating point 표현 방식으로 바꾸는 것
    • 여기서 FPU란 FPU 스택을 말함

Initialization (FINIT)

중요하지 않은 내용이니 대충 보고 넘어가자

  • FINIT 명령어는 FPU를 초기화합니다.
  • FPU 제어 워드를 037Fh로 설정하여 모든 부동 소수점 예외를 숨기고, 반올림을 가장 가까운 짝수로 설정하며 계산 정밀도를 64비트로 설정합니다.
  • 컨트롤 레지스터 값을 바꿀 수 있다 정도만 알고 넘어가자

Floating-Point Data Types

  • QWORD, TBYTE, REAL4, REAL8, REAL10
    • 예) FPU 스택에 부동 소수점 변수를 PUSH할 때, 변수는 REAL4, REAL8, REAL10으로 정의됩니다.
      • QWORD: 64비트 정수
      • TBYTE: 80비트(10바이트) 정수
      • REAL4: 32비트(4바이트) IEEE 단정도 실수
      • REAL8: 64비트(8바이트) IEEE 배정도 실수
      • REAL10: 80비트(10바이트) IEEE 확장 실수

Load Floating-Point Value (FLD)

  • FLD 명령어는 부동 소수점 피연산자를 FPU 스택의 최상위로 복사합니다 (ST(0)로 알려짐).
  • 피연산자는 32비트, 64비트, 80비트 메모리 피연산자(REAL4, 8, 10) 또는 다른 FPU 레지스터가 될 수 있습니다.
    • 여기서 FPU 레지스터는 FPU 스택을 말하는 거임. 즉 스택에 이미 들어 있는 값을 push 할 수 있다.
  • Memory Operand Types
    • MOV와 동일한 메모리 피연산자 유형

FILD (load integer)

integer로 해석하겠다는 것이다. 컴퓨터는 실제 data가 뭔지 모른다. FILD는 지정된 메모리 위치에서 비트를 읽고, 그것을 정수로 해석한 다음, 그 결과를 부동 소수점 값으로 변환하여 처리한다. 이 과정에서 컴퓨터는 데이터의 '원래 형식'은 고려하지 않고, 오직 비트 패턴만이 중요합니다.

  • FILD 명령어는 16비트, 32비트, 64비트 부호 있는 정수 원본 피연산자를 두 배 정밀도 부동 소수점으로 변환하여 ST(0)에 로드합니다.
  • 원본 피연산자의 부호는 유지됩니다.
  • FILD는 MOV와 동일한 메모리 피연산자 유형을 지원합니다.

Loading Constants

이런 것들이 있다 정도만 보고 넘어가자

  • 다음 명령어들은 스택에 특수화된 상수를 로드합니다. 이들은 피연산자가 없습니다:
    • FLD1 명령어는 1.0을 레지스터 스택에 푸시합니다.
    • FLDL2T 명령어는 log₂10을 레지스터 스택에 푸시합니다.
    • FLDL2E 명령어는 log₂e를 레지스터 스택에 푸시합니다.
    • FLDPI 명령어는 π를 레지스터 스택에 푸시합니다.
    • FLDLG2 명령어는 log₁₀2를 레지스터 스택에 푸시합니다.
    • FLDLN2 명령어는 logₑ2를 레지스터 스택에 푸시합니다.
    • FLDZ 명령어는 0.0을 FPU 스택에 푸시합니다.

Store Floating-Point Value (FST, FSTP)

FPU -> mem 저장하는 것

 

FST

  • FST 명령어는 FPU 스택의 최상위에서 메모리로 부동 소수점 피연산자를 복사합니다.
  •  피연산자는 32비트, 64비트, 80비트 메모리 피연산자(REAL4, 8, 10) 또는 다른 FPU 레지스터일 수 있습니다.

  • FST는 스택을 팝하지 않습니다.
    • 다음 명령어들은 ST(0)를 메모리에 저장합니다. ST(0)가 10.1이고 ST(1)이 234.56이라고 가정합니다:
      • fst dblThree ; 10.1
      • fst dblFour ; 10.1

FSTP (store floating-point value and pop)

  • FSTP 명령어는 ST(0)의 값을 메모리에 복사하고 ST(0)를 스택에서 팝합니다.
  •  ST(0)가 10.1이고 ST(1)이 234.56이라고 가정합니다:
    • fstp dblThree ; 10.1
    • fstp dblFour ; 234.56

FIST (store integer)

  • FIST 명령어는 ST(0)의 값을 부호 있는 정수로 변환하여 대상 피연산자에 저장합니다.
    • 사실 소수는 unsigned/signed 구분을 하지 않지만, signed integer로 취급한다.
    • 이 과정에서 자동으로 round(반올림)을 한다.

FCHS (change sign) and FABS (absolute value)

  • FCHS 명령어는 ST(0)의 부동 소수점 값의 부호를 반전시킵니다.
  • FABS 명령어는 ST(0)의 숫자의 부호를 제거합니다.
  • 두 명령어 모두 피연산자가 없습니다.
    • 스택의 TOP에 대해 작동하기 때문

FADD, FADDP, FIADD

 

FADDP : 덧셈 + POP

FIADD : I : Integer, 피연산자 중에 정수가 존재

 

  • FADD
    • 피연산자가 없는 경우, FADD는 ST(0)를 ST(1)에 더합니다.
      • ST(1) += ST(0)
    • ST(0)는 스택에서 팝되어 결과가 스택 최상위에 남습니다.
      • 즉, ST(1)이 새로운 TOP이 되고, 연산 결과가 스택의 TOP에 저장되는 것
    • Register 피연산자
      • Source register가 destination에 더해집니다.
      • 여기서 레지스터는 스택을 말한다
    • 메모리 피연산자
      • 피연산자가 ST(0)에 더해집니다.
        • fadd mySingle ; ST(0) += mySingle
        • fadd REAL8 PTR[esi] ; ST(0) += [esi]

  • FADDP (add with pop)
    • FADDP 명령어는 덧셈 연산을 수행한 후 ST(0)를 스택에서 팝합니다.
      • faddp ST(i), ST(0)
        • Dest : ST(i)
        • ST(0)기 POP

  • FIADD (add integer)
    • FIADD 명령어는 source 피연산자를 double extended precision 부동 소수점 형식으로 변환하여 ST(0)에 더합니다.
      • fiadd m16int
      • fiadd m32int
      • 정수가 소수로 바껴서 스택의 TOP에 더해지는 것

FSUB, FSUBP, FISUB

 

덧셈(FADD, ...)이랑 유사하다

  • FSUB 
    • FSUB는 source 피연산자를 dest 피연산자에서 빼서 결과를 대상에 저장합니다.
      • fsub mySingle ; ST(0) -= mySingle
      • fsub array[edi8] ; ST(0) -= array[edi8]
  • FSUBP (subtract with pop)
  • FISUB (subtract integer)

FMUL, FMULP, FIMUL

 

얘내도 덧셈(FADD, ...)이랑 유사하다

  • FMUL
    • FMUL은 source 피연산자를 dest 피연산자로 곱하여 결과를 대상에 저장합니다.
      • fmul mySingle ; ST(0) *= mySingle
  • FMULP (multiply with pop)
    • FMULP 명령어는 곱셈 연산을 수행한 후 ST(0)를 스택에서 팝합니다.
      • fmulp ST(i), ST(0)
  • FIMUL (multiply integer)
    • FIMUL m16int
    • FIMUL m32int

FDIV, FDIVP, FIDIV

  • FDIV
    • FDIV는 source 피연산자로 dest 피연산자를 나누어 결과를 대상에 저장합니다.
      • fdiv dblTwo ; ST(0) /= dblTwo

  • FIDIV
    • FIDIV는 integer source 피연산자를 double extended-precision 부동 소수점 형식으로 변환하여 나눈 후 ST(0)에 저장합니다.
      • FIDIV m16int
      • FIDIV m32int

6. Comparing Floating-Point Values

comparing 한다는 것은 곧 subtract 한다는 것을 의미한다(앞에서 봤죠?)

  • 두 부동 소수점 값을 비교하려면 FCOM 명령어를 사용합니다.
  • FCOM을 실행한 후, 조건부 점프 명령어를 사용하기 전에 특수 단계를 수행해야 합니다.
  • 모든 부동 소수점 값은 암묵적으로 부호가 있으므로, FCOM은 부호가 있는 비교를 수행합니다.

FCOM, FCOMP, FCOMPP

  • FCOM (compare floating-point values)
    • FCOM 명령어는 ST(0)를 source 피연산자와 비교합니다.
    • source는 메모리 피연산자 또는 FPU 레지스터일 수 있습니다.
  • FCOMP
    • FCOMP 명령어는 동일한 유형의 피연산자와 동일한 작업을 수행하며, 마지막에 ST(0)를 팝합니다.
  • FCOMPP
    • FCOMPP 명령어는 FCOMP와 동일하지만, ST(0)를 한 번 더 팝합니다.

Condition Codes

unsigned 정수 비교에서는 ZF와 CF, signed 정수 비교에서는 SF와 OF를 봤다.

그런데 애초에 FPU는 flag status에 영향을 줄 수 없다. 그러면 comparing 하고 뭘 봐야하는가???

  • 세 가지 FPU 조건 코드 플래그, C3, C2, C0는 부동 소수점 값을 비교한 결과를 나타냅니다.
    • 이들은 각각 Zero, Parity, Carry 플래그와 유사한 기능을 합니다.
  • 두 값을 비교하고 FPU condition codes를 설정한 후 조건에 따라 레이블로 분기해야 합니다:
    1. FNSTSW (Store Status Word) 명령어를 사용하여 FPU Status Word를 AX로 이동합니다.
      1. 연산 결과의 status를 저장하는 것 
    2. SAHF (Store AH into Status Flags) 명령어를 사용하여 AH를 EFLAGS 레지스터에 복사합니다.
      1. FPU status가 CF와 ZF에 매칭되게 설정되어 있다.
  • 조건 코드가 EFLAGS에 있으면, Zero, Parity, Carry 플래그를 기반으로 조건부 점프를 사용할 수 있습니다.

주의할점)!!

실제로 floating point는 signed 이지만, ZF와 CF, above, below를 사용한다

 

P6 Processor Improvements

  • 부동 소수점 비교는 정수 비교보다 실행 시간 오버헤드가 더 많이 발생합니다.
  • Intel의 P6 계열(펜티엄 프로 및 펜티엄 II 프로세서 이후)에서 FCOMI 명령어를 도입했습니다.
    • 이 명령어는 부동 소수점 값을 비교하고 Zero, Parity, Carry 플래그를 직접 설정합니다.
  • FCOMI ST(0), ST(i) 
  • fnstsw ax, sahf를 사용하지 않고 플래그를 확인한다

Comparing for Equality

  • 반올림 오류로 인해 부동 소수점 값을 동등성 비교하는 것은 권장되지 않습니다.
    • 예) (sqrt(2.0) × sqrt(2.0)) - 2.0
      • 수학적으로는 0이어야 하지만, 실제 결과는 상당히 다릅니다(약 4.4408921E-016).
    • ex) 0.2 --> 완벽히 부동 소수점으로 표현 불가

  • 부동 소수점 값 x와 y를 비교하는 올바른 방법은 두 값의 차이의 절대값, |x - y|를 취하고 이를 epsilon이라고 하는 작은 사용자 정의 값과 비교하는 것입니다.

7. Reading and Writing Floating-Point Values

  • Irvine32 라이브러리는 부동 소수점 입출력을 위한 몇 가지 절차를 포함합니다.
    • ReadFloat
      • 키보드에서 부동 소수점 값을 읽어와 부동 소수점 스택에 푸시합니다.
    • WriteFloat
      • ST(0)의 부동 소수점 값을 콘솔 창에 지수 형식으로 씁니다.
    • ShowFPUStack
      • 매개변수 없이 FPU 스택을 표시합니다.

 

8. Exception Synchronization

Concurrency

  • 정수(CPU)와 FPU는 별개의 유닛이므로, 부동 소수점 명령어는 정수 및 시스템 명령어와 동시에 실행될 수 있습니다.
    • 동시성 이슈
  • 이는 unmasked floating-point exceptions이 발생할 때 잠재적인 문제가 될 수 있습니다.

Unmasked exception and its handler

  • unmasked exceptions이 발생하면 현재 부동 소수점 명령어가 중단되고 FPU가 예외 이벤트를 신호합니다.
  • 다음 부동 소수점 명령어 또는 FWAIT 명령어가 실행될 때, FPU는 대기 중인 예외(pending exceptions)를 확인합니다.
    • 대기 중인 예외가 있으면 floating-point exception handler(서브루틴)를 호출합니다.
 

+ Recent posts