# 19章 聯合體
## 19.1 偽隨機數生成器的例子
如果我們需要0~1的隨機浮點數,最簡單的方法就是用PRNG(偽隨機數發生器),比如馬特賽特旋轉演算法可以生成一個隨機的32位的DWORD。然后我們可以把這個值轉為FLOAT類型,然后除以RAND_MAX(我們的例子是0xFFFFFFFF),這樣,我們得到的將是0..1區間的數。 但是如我們所知道的是,除法很慢。我們是否能擺脫它呢?就像我們用乘法做除法一樣(14章)。 讓我們想想浮點數由什么構成:符號位、有效數字位、指數位。我們只需要在這里面存儲一些隨機的位就好了。 指數不能變成0(在本例里面數字會不正常),所以我們存儲0111111到指數里面,這意味著指數位將是1。然后,我們用隨機位填充有效數字位,然后把符號位設置為0(正數)。生成的數字將在1-2的間隔中生成,所以我們必須從里面再減去1。 我例子里面是最簡單的線性同余隨機數生成器,生成32位(譯注:32-bit比特位,非數字位)的數字。PRNG將會用UNIX時間戳來初始化。 然后,我們會把float類型當作聯合體(union)來處理,這是一個C/C++的結構。它允許我們把一片內存里面各種不同類型的數據聯合覆蓋到一起用。在我們的例子里,我們可以創建一個union,然后通過float或者uint32_t來訪問它。因此,這只是一個小技巧,而且是很臟的技巧。
```
#!cpp
#include <stdio.h>
#include <stdint.h>
#include <time.h>
union uint32_t_float
{
uint32_t i;
float f;
};
// from the Numerical Recipes book
const uint32_t RNG_a=1664525;
const uint32_t RNG_c=1013904223;
int main()
{
uint32_t_float tmp;
uint32_t RNG_state=time(NULL); // initial seed
for (int i=0; i<100; i++)
{
RNG_state=RNG_state*RNG_a+RNG_c;
tmp.i=RNG_state & 0x007fffff | 0x3F800000;
float x=tmp.f-1;
printf ("%f
", x);
};
return 0;
};
```
清單19.1: MSVC 2010 (/Ox)
```
#!bash
$SG4232 DB ’%f’, 0aH, 00H
__real@3ff0000000000000 DQ 03ff0000000000000r ; 1
tv140= -4 ; size = 4
_tmp$= -4 ; size = 4
_main PROC
push ebp
mov ebp, esp
and esp, -64 ; ffffffc0H
sub esp, 56 ; 00000038H
push esi
push edi
push 0
call __time64
add esp, 4
mov esi, eax
mov edi, 100 ; 00000064H
$LN3@main:
; let’s generate random 32-bit number
imul esi, 1664525 ; 0019660dH
add esi, 1013904223 ; 3c6ef35fH
mov eax, esi
; leave bits for significand only
and eax, 8388607 ; 007fffffH
; set exponent to 1
or eax, 1065353216 ; 3f800000H
; store this value as int
mov DWORD PTR _tmp$[esp+64], eax
sub esp, 8
; load this value as float
fld DWORD PTR _tmp$[esp+72]
; subtract one from it
fsub QWORD PTR __real@3ff0000000000000
fstp DWORD PTR tv140[esp+72]
fld DWORD PTR tv140[esp+72]
fstp QWORD PTR [esp]
push OFFSET $SG4232
call _printf
add esp, 12 ; 0000000cH
dec edi
jne SHORT $LN3@main
pop edi
xor eax, eax
pop esi
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
```
GCC也生成了非常相似的代碼。
- 第一章 CPU簡介
- 第二章 Hello,world!
- 第三章? 函數開始和結束
- 第四章 棧
- Chapter 5 printf() 與參數處理
- Chapter 6 scanf()
- CHAPER7 訪問傳遞參數
- Chapter 8 一個或者多個字的返回值
- Chapter 9 指針
- Chapter 10 條件跳轉
- 第11章 選擇結構switch()/case/default
- 第12章 循環結構
- 第13章 strlen()
- Chapter 14 Division by 9
- chapter 15 用FPU工作
- Chapter 16 數組
- Chapter 17 位域
- 第18章 結構體
- 19章 聯合體
- 第二十章 函數指針
- 第21章 在32位環境中的64位值
- 第二十二章 SIMD
- 23章 64位化
- 24章 使用x64下的SIMD來處理浮點數
- 25章 溫度轉換
- 26章 C99的限制
- 27章 內聯函數
- 第28章 得到不正確反匯編結果
- 第29章 花指令
- 第30章 16位Windows
- 第31章 類
- 三十二 ostream