>>> hi, lo = veltkamp_split(pi)
>>> hi + lo == pi
True
>>> hi.hex()
'0x1.921fb58000000p+1'
>>> lo.hex()
'-0x1.dde9740000000p-26'
Note all the trailing zeros and the difference between the two exponents. Also both the lo and hi values are signed.
Use case: The 26-bit precision components can be multiplied losslessly (without rounding):
# Four exact components of e * pi:
>>> pi_hi*e_hi
8.539734226211163
>>> pi_hi*e_lo
7.207993525551209e-08
>>> pi_lo*e_hi
-7.561753118743836e-08
>>> pi_lo*e_lo
-6.382525038592985e-16
The payoff for Veltkamp-Dekker splitting and piecewise multiplication is that you can build quad precision arithmetic out of everyday double precision arithmetic.
The part that is pure magic: How do you split a 53 bit number into two 26 bit numbers? Where did the extra bit go?
Answer: The extra bit is stored in the sign bit of the "lo" component.
* Replacing literals with variables and named constants
* Replacing literals with regexes
* Replacing literals with function calls
* Replacing literals with set membership tests
We draw key learning points from real #Python applications:
* Datetime formatting mini language
* Language tokenizer
* SQL logic for JSON lines
* SQL logic for two level JSON
* Traversing arbitrary depth JSON trees
* Marshal style data serializer
#Python tip: The default_factory feature of a defaultdict is only useful when building up a dictionary (automatically adding missing keys).
However, that feature is a menace when doing lookups (risking accidental dict mutation).
Consider converting back to a regular dict.
1/
# During build-up, we want the factory magic.
d = defaultdict(list)
for elem in data:
d[feature(elem)].append(elem)
# Magic is no longer useful.
d = dict(d)
# Lookups are now safe.
print(d[some_feature])
2/
Converting back to a regular dictionary is cheap.
The hash values are reused rather than recomputed. The new dict is presized in a single step. The key and value pointers are copied rather than inserted. The only slow part is updating all the reference counts.
3/
#Python news: It was always awkward to write a type annotation for methods that returned self (an instance of the current class). As of yesterday, typing.Self was added to make this much easier and more readable.