In de aflevering van vandaag van programmeerhorror... In de Python-documentatie van random.seed() def, wordt ons verteld "Als a een int is, wordt deze direct gebruikt." [1] Maar als je zaait met 3 of -3, krijg je eigenlijk exact hetzelfde rng-object, dat dezelfde streams produceert. (TIL). In nanochat gebruikte ik het teken als een (wat ik dacht dat een) slimme manier was om verschillende rng-sequenties te krijgen voor train/test splits. Vandaar de vervelende bug omdat nu train=test is. Ik vond de CPython-code die verantwoordelijk is in cpython/Modules/_randommodule.c [2], waar we op regel 321 in een opmerking zien: "Dit algoritme is afhankelijk van het feit dat het getal unsigned is. Dus: als de arg een PyLong is, gebruik dan de absolute waarde." gevolgd door n = PyNumber_Absolute(arg); wat expliciet abs() op je zaad aanroept om het positief te maken, waarbij de tekenbit wordt weggegooid. Maar deze opmerking is eigenlijk ook verkeerd/misleidend. Onder de motorkap roept Python het Mersenne Twister MT19937-algoritme aan, dat in het algemeen 19937 (niet-nul) bits staat heeft. Python neemt je int (of andere objecten) en "verspreidt" die informatie over deze bits. In principe had de tekenbit kunnen worden gebruikt om de staatbits te vergroten. Er is niets aan het algoritme dat "afhankelijk is van het feit dat het getal unsigned is". Er is een beslissing genomen om de tekenbit niet op te nemen (wat imo een fout was). Een triviaal voorbeeld zou kunnen zijn om n -> 2*abs(n) + int(n < 0) te mappen. Uiteindelijk leidt dit ons naar het contract van Python's random, dat ook niet volledig is uiteengezet in de documentatie. Het contract dat wordt genoemd is dat: zelfde zaad => dezelfde sequentie. Maar er wordt geen garantie gegeven dat verschillende zaden verschillende sequenties produceren. Dus in principe doet Python geen beloftes dat bijvoorbeeld seed(5) en seed(6) verschillende rng-stromen zijn. (Hoewel dit vrij algemeen impliciet wordt aangenomen in veel toepassingen.) Inderdaad, we zien dat seed(5) en seed(-5) identieke streams zijn. En je zou ze waarschijnlijk niet moeten gebruiken om je train/test-gedragingen in machine learning te scheiden. Een van de meer amusante programmeerhorror-foutjes die ik recentelijk ben tegengekomen. We zien je in de volgende aflevering. [1] [2]