A correction: "If the callee wishes to use registers RBX, RSP, RBP, and R12–R15, it must restore their original values before returning control to the caller. All other registers must be saved by the caller if it wishes to preserve their values." These are callee-preserved Not caller-preserved Implications here: 1. Feel free to use RBX and R12-15 to preserve values when calling a function 2. Don't bother preserving them before function calls 3. But you have to put the values back before finishing your function How have we been getting away with this? Haven't been writing many functions Surely everyone is tired of integers by now! You could multiply everything by 1,000 and have millisecond precision in the simulation... Wouldn't that be easier than floating point? Oh well, floating point. First: It comes in sizes float: 32-bit (single-precision) double: 64-bit (double-precision) long double: 80-bit usually, 128-bit on some architectures __float128: 128-bit (quad-precision) "Q" suffix if defining a constant printf doesn't really support these. quadmath_snprintf will do it Kinda like integers: char: 8-bit short: 16-bit int: 32-bit long: 64-bit (on all but Windows) __int128 128-bit (C23 standardized this, but it was around earlier) Note: x86-64 totally supports 128-bit math And has for a long time C/C++ have just been lagging on standardized support For today, we'll use single-precision A neat trick we'll use today: gcc -S Eat this elephant a bit at a time... Simple program that just prints out a float Interpreting our float: Wikipedia single-precision diagram 1 byte for the sign 8 for the exponent 23 for the fraction (or significand) Kinda 24 - there's an implied 1 at the beginning Encoding the sign It's a bit The bit is the sign Let's change it and see what happens The exponent: 8-bit integer, but 127 is subtracted from it What's anything raised to the 0th power? Remember, the sign goes first 0x7f8 would set all bits to 1 That's called "inf" Bias: Subtract 127 for actual exponent Let's do some powers of 2 The fraction, or significand: 2 is implied (so we've been leaving it 0) Place value: 1, 0.5, 0.25, 0.125, etc Table on Wikipedia Can we print out a 3? How about something harder, like 7.25? Alright, programming with these: There are a couple ways Olden days: x87 Has a stack of 8 registers Common these days: SSE That's what gcc seems to use xmm0 etc registers Newer: Advanced Vector Extensions Maybe "newer" isn't ok to say here anymore... A shortcut: We'll make a function that works with floating point Add a couple numbers My bug from testing this earlier Think "How would the compiler know..." How about multiplication? Epilogue: Performance and floats This one seems ok: https://www.servethehome.com/nvidia-geforce-rtx-3090-review-a-compute-powerhouse/3/ 3D graphics mostly uses single-precision Vector extensions on the CPU: These head toward GPU operations, a little, kinda SIMD, as in "Streaming SIMD Extensions" But the GPU does this way better