perf(math): scan least significand bit with MSVC x64 intrinsic
This commit is contained in:
@@ -163,6 +163,31 @@ trap 관측까지 동등하다고 주장하지 않는다. 원래 분류의 새
|
||||
[검사 로그](../../.harness/performance/shared-classification/after-checks.txt)를 보존한다.
|
||||
이 결과는 최종 모델의 시간 목표나 전체 회귀 검사를 대체하지 않는다.
|
||||
|
||||
후속 동적 Hex8의 30초 SW raw 자료에서는 `LowestBitExponent`가 51.037592
|
||||
sampled CPU초로 나타났다. 150초 제한의 개발 실행은 완료되지 않았으며 이 값은
|
||||
전체 경과 시간이나 개선 배수가 아니다. 공통 산술 담당자는 MSVC 호환 x64 macro
|
||||
조건에서만 6단계 trailing-bit 검색을 `_BitScanForward64`로 교체했다.
|
||||
[Microsoft 계약](https://learn.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64?view=msvc-170)의
|
||||
least-set-bit index를 사용하며 정상 수의 implicit bit와 비영 subnormal fraction이
|
||||
mask가 0이 아님을 보장한다. Exponent 구성, -1074 exact-tail 거부, FMA와
|
||||
모든 pair 산술식은 그대로다. Macro 조건 밖에서는 기존 portable 검색을 유지한다.
|
||||
MSVC 호환 macro를 정의하는 다른 compiler의 실행까지 검증했다고 주장하지 않는다.
|
||||
|
||||
[독립 source 수치 검토](../../.harness/performance/shared-bitscan/source-numerical-review.md)는
|
||||
이 검색값과 downstream gate 보존을 확인했다. 정확한 include dependency를 가진
|
||||
MSVC Debug에서 unit/integration/CLI consumer를 36개 edge로 재빌드했고,
|
||||
기존 frozen exponent·pair bit oracle와 통합 Hex8·paired state/kinematics·직렬/TBB
|
||||
검사 **68/68이 native 0**으로 통과했다.
|
||||
[실행 기록](../../.harness/performance/shared-bitscan/after-native.json)과
|
||||
[검사 로그](../../.harness/performance/shared-bitscan/after-checks.txt)를 보존한다.
|
||||
새 검색의 전체 동적 시간, 최종 reference 및 전체 Debug 판정은 아직 미실행이다.
|
||||
|
||||
통합한 Hex8의 ordinary MKL 연산, 원래 누적·진단 순서, private pair의 영항 생략과
|
||||
선택적 선형 tangent의 지연 준비는 [전용 기록](hex8-performance.md)에 있다.
|
||||
선택적 준비는 Float64 Create의 필수 검사를 바꾸지 않으며 검증된 현재 trial의
|
||||
요청에서만 초기화한다. 해당 기록의 1.7391958초는 과거 a08 source의 개발 단일
|
||||
실행이고 최신 통합 source의 공식 시간 합격으로 소급하지 않는다.
|
||||
|
||||
위 검증 중 기존 MSVC/Ninja의 include prefix 인식 오류도 확인했다. 이 PC에는
|
||||
한국어 compiler resource만 있어 `VSLANG=1033`만 지정한 fresh build도 dependency가
|
||||
0개였다. 실제 출력 접두사 `참고: 포함 파일: `를 별도 로컬 CMake include로 지정한
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#if defined(_M_X64) || defined(__SSE2__)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
@@ -114,8 +117,14 @@ inline int LowestBitExponent(double value) {
|
||||
? -1074
|
||||
: static_cast<int>(encoded_exponent) - 1075;
|
||||
if (encoded_exponent != 0U) significand |= 1ULL << 52U;
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
// The finite, nonzero precondition makes the significand nonzero.
|
||||
unsigned long trailing = 0;
|
||||
_BitScanForward64(&trailing, significand);
|
||||
return exponent + static_cast<int>(trailing);
|
||||
#else
|
||||
int trailing = 0;
|
||||
// Strip large zero groups first without vendor/compiler intrinsics.
|
||||
// Preserve the portable search outside the supported MSVC x64 path.
|
||||
for (const int shift : {32, 16, 8, 4, 2, 1}) {
|
||||
const auto mask = (1ULL << shift) - 1U;
|
||||
if ((significand & mask) == 0U) {
|
||||
@@ -124,6 +133,7 @@ inline int LowestBitExponent(double value) {
|
||||
}
|
||||
}
|
||||
return exponent + trailing;
|
||||
#endif
|
||||
}
|
||||
/// @brief Gives a product and its FMA residual when the dyadic tail fits.
|
||||
/// @note Rejects underflow-risk exact tails, even if the rounded high is finite.
|
||||
|
||||
Reference in New Issue
Block a user