Chris X Edwards

It's interesting how military service decorations understood gamification centuries ago.
2024-04-17 07:56
When my software has weird bugs because of floating point encoding, the blame really lies with my math education as a kid. Fixing it slowly.
2024-03-16 10:49
Real bank security posture shouldn't send statements with 7 small opaque (to me) QR codes with the redundancy to defy shredding. @BofA_Help
2024-03-05 14:15
I can only smile like ad models in stock photos at the disconnect between their reaction to, say, car financing and the real experience.
2024-03-05 13:13
How gauche my USA neighbors think clothes hanging on a line looks is exactly how gauche clothes look hanging on them.
2024-02-23 12:41
Blah Blah
--------------------------

Downhill Wax

2024-04-22 13:30

Today I was prepping my (Nordic) skis with summer wax; I’ll refrain from delving into what that even means. However I recently came to possess some very used Alpine skis and looking at their bases made me want to make a little PSA for the motorskiers I know.

If you own skis that only are supposed to go down mountains, do you need to wax them? In my opinion, yes. Take a look at these skis where I have just waxed the one on the right.

wax-no_wax.jpg

I would not be surprised if this is their first wax since being new. I thought this was an interesting shot to illustrate what it looks like when the bases are absolutely stripped and dry.

Ok, sure it looks like wax changes the look of the bases, but is that really important? Consider the following. Oiling the chain on a bicycle is not optional; if you don’t do it eventually it will become painful to pedal. However, never oiling the chain on a motorcycle won’t ever make you sweat more. But leaving a motorcycle chain dry will cause squeaking, rattling, vibrations, and terrible gas mileage. It is unsafe and basically a terrible idea.

You may think that since you’re not a downhill ski racer that you don’t need to go fast, and so you don’t need properly prepared bases on your downhill skis. Perhaps you think the more friction you have, the better it is for not zooming out of control into a tree. Or something like that. Unfortunately it doesn’t quite work that way. By skiing on dry skis with all wax totally worn off you’re going to have a lot more problems with control and predictability. The skis will subtly stutter and create stability problems. With smooth sliding skis you’ll be able to slip predictably into turns that can keep things under control with less effort.

Just like anyone who regularly rides a bicycle appreciates chain lube in the same way that elite professional motorcycle riders do, so too do all Nordic skiers appreciate ski glide like elite professional Alpine skiers. After a lot of very personal blood, sweat, and tears relating to ski wax I can offer some tips.

I think that for normal people (e.g. no more skiing power than me) you can count on about 50km of good skiing with a wax job. I think that 100km is ok skiing but getting worse, and beyond that things start to fall apart and get very bad quickly. Also the first 1km or so after you get your skis waxed can be the worst 1km. This is probably less of a problem for Alpine skiers who can use the motor/gravity to press through this, but if that first run feels terrible, check again on the second run.

Another thing to note is that switching ski sides is helpful. When you start wearing down the wax, you’ll see the dry rough p-tex (as in the comparison photo) start to appear in the areas you generate the most friction. By switching sides you can get a lot more life out of the wax.

Also without getting too nerdy about wax, we all kind of know what wax is and we know that if someone puts, say, a candle or a crayon in a hot car that it will likely make a mess. That ordinary intuition will serve you well if you remember that there is a microscopically thin layer of delicate wax on your skis and avoid situations like leaning them up against the heater in your hotel room, etc.

I actually am not an expert at all on exactly what Alpine skiers (or snowboarders) should do but it probably is very close to what I’m fastidiously doing with my Nordic skis: 1. Clean with a base cleaner to get dirt, sap, and other contaminants out. 2. A base prep wax applied with a ski wax iron; scrape that out hot and it will pull out more impurities and gunk. 3. A layer of harder wax; scrape cold. Then a layer of warm temperature wax (unless you know where global warming isn’t in effect), and scrape that cold. 4. Finally brush with bass, horsehair, and nylon brushes in that order.

Or do whatever the folks at the ski shop suggest. But what you don’t want to do is be oblivious to the fact that all ski bases need glide wax applied from time to time because it does wear off. Take it from someone for whom every skiing watt is meticulously conserved, the difference between skiing with and without proper wax is really the difference between skiing and melting snow by strapping boards to your feet.

Review - Carmageddon

2024-03-29 21:29

I get my "news" by reading last quarter’s copies of The Economist. They recommended this book and its author, Daniel Knowles, was their Africa correspondent for 3 years, so I thought I’d check it out. The premise of this book is that cars are bad. That message is preaching to the choir for me, someone who has been fighting the evils of cars for over thirty years. While my life’s work to save humanity from an infestation of parasitic cars has generally been a failure, it does look like some people are slowly catching on that the problem is actually a problem.

The idea that cars might be more enslaving than liberating is now starting to find some footing for a slightly broader audience. Popular and righteous YouTuber CityNerd has a good video on the topic which normal people are encouraged to watch. Nerdier people are encouraged to read the paper he cites: Car Harm: A Global review of automobility’s harm to people and the environment (Miner,Smith,Jani,McNeill,Gathorne-Hardy) If you’re really interested in the topic, you can do all that and read this book.

After talking about how everybody appreciates the exhilaration of driving fast while unmolested by other idiot drivers, the book offers this description of The Problem.

The problem is that cars impose costs on everybody else. The are among the world’s leading causes of what economists call "externalities" — costs imposed on others by your decisions. …your freedom to get around in your personal steel bubble is another person’s freedom to have their lungs poisoned. Probably a much poorer person than you too. When you are sitting in traffic, you are not just being slowed down by everyone else, you are slowing them down too. When everyone drives to work, the car parking space uses land that could be used to build houses. When you burn gasoline … to get around, the CO2 emitted helps to heat up the entire planet. And of course, if you crash, you are far safer inside your metal box than the pedestrian you hit on the road. According to a study by the city of Copenhagen, every kilometer driven there costs society fifteen euro cents in higher pollution, congestion, and accident costs. Cycling a kilometer, by contrast, generates sixteen cents of benefits [from lower healthcare spending].

I feel like this is a bit muddled, but really, where do you start? It’s like having the premise that genocide is bad — where do you even start? With the obvious or the subtle? The book goes on to haphazardly hammer away at various aspects of car culture’s awfulness but that doesn’t make any of the arguments wrong.

On page 11 he comes up with some research that puts a dollar amount on commuting: apparently $40k is the pay cut people will take to not have to do it. (Is this the US? The average 32min each way commute?) For me personally it’s way higher! He mentions the car friendly awfulness of Houston which is no lie. If I’m reading page 88 right, it looks like he’s saying (car produced?) air pollution kills as many people per year as a C19 pandemic. The book claims (p182) that in 2021 790k electric bicycles were imported to the US while 690k electric cars were purchased. That’s kind of interesting if true. The author asserts (p164) that "right on red" is a dangerous American habit, but no statistics are given. I wonder, how is it much worse than the British roundabout he (probably rightly) lauds for being a relatively safe feature (e.g. T-bone crashes are rare in Britain). Anyway, the book is duly peppered with factoids like this.

On page 86 he brings up something I have no doubt is true. "Buses are way cheaper… But officials do not like them, for precisely that reason: Unlike other big construction projects, they do not generate big contracts with the possibilities for kickbacks." Now, I can vouch for this one myself because when my job was to build expensive computer installations, I had many discussions with people where I would tell them, "Hey, maybe you don’t need a whole new cluster of 500 computers; perhaps we could optimize your software to be more efficient." And they get an uncomfortable look and say, "Heh heh, ya, that’s, uh, interesting, but look, our grant puts us in charge of $X_million for computers so let’s build that cluster, ok?" Or, they say, "Hey we need a $X_million computing installation." And I say, "Oh, great, what do you need it to do?" And they say, "Cost $X_million to increase our budget." The idea that traffic engineering departments could cure a lot of their problems by not pissing away money on massive projects that will have perverse effects thanks to induced demand is not what they want to hear. And, yes, induced demand is covered, just as it is in the 2008 book Traffic which I reviewed in 2017.

Chapter 10 basically covered Shoup just as I did six years ago. Essentially "free parking" is not free. He did have some fine examples of the madness of this form of bright red communism: 0.5 parking spots are required for every resident of a nursing home and a full space is required for every 500sqft of cannibis retail. Same with bars. Really the number one thing that can be done to make transportation less evil/car-centric is to introduce a crazy invention called the free market and price parking properly according to land value. By doing away with the totalitarian communist parking space requirements whose costs are passed along to society, a lot of the problem would go away naturally.

In Holland in the early 1970s their enviable shift to reasonable bicycle infrastructure apparently came from a campaign called "Stop The Child Murder". Sadly that’s not something Americans are too concerned about if the country’s stance on universal healthcare for children is anything to go by. Sorry, but I’m going to shame Americans at every opportunity until that’s fixed.

Chapter 7 is devoted to the problems of electric vehicles. He offends Musk fan-boys by bringing up inconvenient facts like particulates are not improved with electric cars (indeed worse because of heavier vehicles), same with (tire) noise, if coal powers your grid they might release more CO2 than hybrids, the Congolese are getting raped, the grid really can’t sustain everyone using it for transportation, etc, etc. Look, I can’t see electric cars as any kind of panacea either but I think the author understands they have some potential to help somehow with something. Whatever. The whole electric car thing does seem like a distraction, but I’ll leave that for other people to worry about because I don’t really care.

What I do care about is the topic of chapter 8. This chapter is a poorly thought out critique of autonomous cars. The main argument seems to be based on name-calling, with the concept of computers handling the driving being mocked as "bionic duckweed" (which can be understood to mean "ridiculous boondoggle"). Now, I do not defend the stupidity and failure of imagination that runs the autonomous car business. There are serious problems in that industry. However, I think the author is pretty lame to pick on self-driving cars in 2023. Back in 2016, when I said there were serious problems with how things were being envisioned, well, that was a bit bolder. And 100% correct in hindsight. So with my better track record, let me set the author straight on some things.

He says with respect to autonomous cars, "Roads will supposedly become safer and more efficient." Supposedly? Bro, have you been on a public road? When that guy eating his Taco Bell and watching porn on his telephone is also trying to drive an enormous F150 what the fuck could possibly be less safe? For some reason a million deaths by human drivers is ok, but one death by a computer control is unacceptable. Well, since I’m personally at the front of the line for getting slaughtered in the street, and I can do basic math, I’m not too keen on that thinking. The author acts like he’s the first person to think of the brilliant idea that everyone should use public transportation. People like me have been there and done that. Dude, not happening. Go tell all the junkies of the world to stop injecting heroin — you’ll have better luck. The only way the problem is less problematic is to put car drivers in a cage where they can’t hurt anybody. I think there is no fundamental technical reason why computer control could not be that cage. And rather than telling these junkies that they have to kick their habit, I feel like you’ll have more luck telling them they can have 100x more of the texting in a single occupancy car that they’re addicted to. But, hey, that’s just my opinion.

He mentions that it is ridiculous to factor in autonomous technology in any kind of infrastructure decision making and long term planning. Why? How could this be sensible? He scoffs at the idea of a transformative technology springing into existence yet then contradicts himself by acknowledging that the internal combustion engine did just that. On p107 he admits SpaceX is no "bionic duckweed". I am certain that cheap sensors and parallel processing combined with astonishingly accurate neural networks are also no trifling minor detail. These are a big deal and how we take advantage of them is up to us.

He seems to not understand how AI works in vehicle robotics applications. He is concerned that it has to "rely on what scientists call machine learning". He goes on to show his ignorance by imagining this as "they have to rely on the computer training itself, by making mistakes and being corrected. Trial and error." Ok, first off, how do you think human drivers train themselves? I’m afraid it’s trial and error. But that shows a profound misunderstanding of machine learning as applied to vehicle robotics. There are many things a vision system can’t do as well as humans. But does he realize there are many, many, many things that automated systems can do with AI voodoo that outperform humans by orders of magnitude? 24/7 without ever being drunk.

On p105 he brings up the Uber crash. (Which I covered in detail years ago here and here and here.) For fuck’s sake man, this is a beautiful perfect example of why autonomous cars are essential: you can give a driver all the help in the world, pay them a salary to pay attention and they will still fail at their job. To blame a test system is bullshit. The designers knew it was a test system and put a failsafe human in the loop. The surprise wasn’t that the system being tested failed when it encountered unfamiliar conditions; the surprise was that the human failed because humans suck at driving safety. While transportation safety depends on continuous human attention there is no transportation safety!

What he really seems annoyed with is using magical robo-taxi dreams to not confront reality properly. To an extent that’s reasonable, but I also disagree with him because I would claim that some of that robotic technology is relevant to the discussion. He says, "…when self-driving car advocates argue that their rise will mean that technologies such as trains will be made redundant… they are almost certainly wrong." Let’s just walk through this with a little more substance and nuance. Like The Economist would. Let’s ask ourselves what are trains for? Why trains? What is a train? Why would you use a train? Well, there are two reasons. The first one is that you don’t need to steer a train — it is guided by tracks. (Let’s not even get into the weird, weird, weird situation where trains need "drivers" who can not really even do anything meaningful to control the train. This is usually a political/union thing and not a technical decision.) So the tracks mean you don’t have to steer your vehicle — great. You know what other kinds of vehicles do not need steering? All of them! Today no vehicles need to be steered by a human. If you have a route you’d like to run like a train, you can make pretty much any vehicle run it. If I personally singlehandedly can make a dumb speedboat run a route within the width of a railway corridor, it is a solved problem. Right away, people miss the point and jump to conflate this technical marvel with not mowing down things/people that should not be run over. That is a completely separate problem. If you just can’t get that problem out of your head, take it as completely solved the exact same way trains solved it in the early 19th century by clearing the tracks and maintaining a right of way.

Ok, so now we can see that you can put down a pair of steel rails or you can now put down two strips of cheap concrete pavers (or nothing, just grade it) and your vehicle will not stray from your planned path. What’s the real difference then? The profound advantage steel rails have over other systems is that the rolling resistance is much lower. Sometimes this is the ideal parameter to optimize as when you are maximizing the amount of mass you need to move. Are you moving as much ore as you possibly can from the Australian interior to ports and processing centers? Steel rails is probably the way to go. But aren’t you always optimizing for moving mass? No! Steel wheels (that match steel rails) are heavy. They take a lot of energy to accelerate up to speed. If your vehicle makes frequent stops, the case for steel rails is not so strong. Another situation where steel wheels may not be optimal is when the load demands are quite variable. For example, sometimes you need to move a full train and sometimes it’s mostly empty. What kind of transportation systems make frequent stops and often have high variability in their loading? Well, the exact kind of public transportation networks that maybe should be thinking through all of the alternatives when making difficult-to-reverse decisions that will deeply impact the future. Oh and another consideration for high density transportation planning: rubber tires are incredibly loud and obnoxious under serious momentum loading but train wheels are worse! This is why you can hear a train at night 5km away. To scoff at vehicle automation as nonsensical just because Elon Musk has indeed been silly with foolish prognostications of his companies' miraculous products is its own kind of nonsense. Baby. Bathwater.

(Check out this fine video about train rolling resistance subtleties if you would like to understand the trade-offs better.)

It’s frustrating that (p110) the author wants to lump "autonomous driving" with "stupid driving". I get it. Having everyone sit in their own autonomous car would probably create induced demand where the computer could economize the road usage (higher speeds, closer following, idealized planning, less dipshittery and crashes, etc). But remember that people trapped in computer controlled traffic doing whatever they want is way more righteous and correct than having them suffer in their cars while insisting they pilot those cars in a way that does not murder me. They can all burn in hell. The whole planet can burn in hell. My priority is not being murdered in the short term, thanks. But ya, definitely give some thought to the more holistic stupidity that has gripped our transportation Zeitgeist. Autonomous car tech, IMO provides a way to make a clean break from the old way and for pricing in the externalities properly. If someone wants a planet destroying ride in a private car because randos are gross, fine, but they should pay 10x for that. Correctly designed autonomous systems can provide that flexibility in theory. In practice? Who knows. The whole world is insane when it comes to transportation and I don’t see that magically turning around any time soon.

Whew! Let’s take a deep breath and relax now since that’s the end of my rant about autonomous car technology not being properly given a chance to sensibly ameliorate the disaster of cars.

On to Chapter 11… Wow, that Volkswagen emissions thing was a real shitshow. Car companies are really just awful in pretty much every way. This book didn’t even cover the auto industry’s shitty record with safety cover-ups. The fact that politicians hold up (and bail out) auto makers as paragons of society and providers of "good" jobs is a ludicrous misallocation of societal good will.

On to Chapter 12… More fun trivia: apparently a Sherman tank (5.84 x 2.62 x 2.74m) was about the same size as a modern F150 (the longest that I know about is the SuperCrew at 6.17m). This chapter talked about the absolute madness of CAFE standards and how selling efficient cars means you can also then sell polluting ones in a global sense. Tesla apparently is cleverly subsidized by this somehow. (p153) "Before 2022, Tesla was making more from selling the right to pollute to other car firms than it was in profit from selling its own cars." But that’s hardly a big win for the environment. It is pointed out that a clean car is good, but "if you buy a Tesla, or another electric car, you are not in fact taking a whole car’s emissions off the road. Rather you are just giving somebody else a license to pollute a little more. As long as the CAFE standards remain as they are, individuals buying electric cars cannot do much to improve the overall level of climate change emissions, because the car industry will continue to aim [for] the overall target."

I found this quote on page 178 funny and wrong: "Safety concerns are why cyclists in cities in the United States, and indeed much of Britain, tend to be Lycra-clad young men who thrive on the adrenaline rush of weaving through traffic to get around." Let me stop you right there, Dan, and correct this. I live where I can watch cyclists all day long on one of the world’s most magnificent bicycle highways — indeed I am doing so as I type this — and I can tell you that the Lycra tends to be correlated with age. There is a reason that MAMIL, a Middle Aged Man In Lycra, is a thing.

But it is far more important to note a bigger misconception in that quote. Even truculent fuckers like me — who have been very close to pulling assholes right through the safety glass of their stinking automotive cocoon to beat them to death with a U-lock — do not thrive on constantly being the victim of attempted murder. We actually fucking hate it. What you are really seeing when that "crazy" guy passes your car on a bike mixing it up in traffic like he has a death wish is the extreme end of the bell curve for defiance. He is Spartacus! That guy would rather be dead than a cowardly slave to everyone else’s world destroying cars. How many bicycle mounted thrill seekers do I see running with cars where there is a perfectly sensible alternate route to safely ride a bicycle? Zero. It never happens. So that attitude is wrong. And (as mentioned on p180-181) if that crazy cyclist can survive, his life expectancy is going to be statistically way higher than that pathetic fat coward stuck in traffic in his monster truck emotional support vehicle.

And that’s all I have to say about this book. Cars are shit. Cars are shit. Cars are shit. If that’s kind of a shocking idea for you, maybe you need to read this book. But if you know me personally, well, you probably know that cars are shit and exactly why. I hope this book finds a new audience and does some good.

truckguys.jpg

Review - Cassell's Latin-English Dictionary

2024-03-28 18:33

I like hobbies that are unusual and challenging, generally to the point where normal people can no longer really comprehend the experience as sane. When it comes to reading I’ve been known to tackle challenging books. Despite reading most every day, this winter I managed to get through only half of one book. That book was Cassell’s 1959 Latin-English Dictionary.

I can’t say cover to cover because I stopped at the English-Latin section. The entire book has 928 pages and early on I thought it would be a reasonable challenge to read half that. Only as the P’s dragged on past the halfway mark did I realize that for some reason, the Latin-English pages outnumbered the English-Latin by two to one (628/300). This was physically a hard book to read too. My eyesight is no longer as good as human eyesight can possibly be but for my age it’s still not bad and I usually do not wear glasses when reading. With this book however, the font size was microscopic and the alien nature of the content and Latin example citations made reading glasses essential. The (ironically named) italic font, greek letters, and microscopic symbols throughout were a challenge too.

latin081.jpg

So why would somebody want to do this possibly unpleasant sounding thing? I will start by saying that I did enjoy it. I am glad I did it and consider the experience worthwhile. The first thing to consider is that by reading the entire thing I was treating this dictionary more like a book than a reference. If I need to look up a word in a foreign language computers do a fine job. Consider any book you’ve ever read — if it was more than a few weeks ago, the amount of specific detail you remember is next to nothing. Does that make the value of reading books next to nothing? No. Reading books is a way to really immerse yourself in a topic or story. It allows the neural networks of your mind to become stronger when thinking about the topics or themes. Recalling what some minor character did in a novel you read five years ago is not important. Mostly what you retain about such reading is that, yes, you have read that book and you either liked it or not. Occasionally there are some specific insights so important that you hang onto them too. (For example, it is bad to wake up as a cockroach! Etc.) Suffice it to say, I did not memorize any of this dictionary and I am still a poor replacement for its ordinary purpose.

But, wow, I sure did get a sense of the Latin language! Quickly reading through a simple (phonetic pronunciation) dictionary is one of my recommended techniques to learning the scope and nature of a foreign language. This one was not simple but it definitely served the same purpose of really immersing a learner in the full scope of the language.

latin228.jpg

One interesting example of how reading a Latin dictionary can be helpful in understanding the scope of the language is prefixes. Latin is a heavily inflected language. This means that a core vocabulary is tweaked in small ways to convey complex meaning. For example, Latin (and any modern Romance language) is famous for its inscrutable verb conjugations. But reading all the words in alphabetic order highlights the rich character of the beginning of words too. I didn’t explicitly count, but it seemed to me that most words were in prefix blocks which will mostly be familiar to English speakers. Prefixes like "com-", "con-", "de-", "di-", "ex-", "im-", "in-", "ob-", "par-", "per-", "prae-", "pro-", "re-", "sub-", and "trans-" should look familiar and important to most people speaking any European language. Reading a dictionary really helps you very deeply understand what those prefixes are all about and how they got that way. After seeing dozens of examples of how a prefix is used, you start to feel like you could, uh, re-in-vent some new words using them correctly. We do that and so did Latin speakers.

Ok, so reading a Latin dictionary is possibly helpful in learning about Latin. Great. The bigger question remains, why would you want to do that? If it’s not clear by now, my real goal is not reading ancient texts but rather better understanding my own native language. English is packed with Latin! I like to read Merriam-Webster’s daily Word-Of-The-Day and one day it explicitly stated the following facts.

Many of the words we use in English can be traced to one of two
sources: about one-quarter of our vocabulary can be traced back to
English's Germanic origins, and another two-thirds comes from Latinate
sources (most such words come by way of French or from Latin directly,
but Spanish and Italian have made their contributions as well).

The M-W Word-Of-The-Day is actually a very interesting resource. Let’s look back on the week’s previous words: flout, kismet, megillah, auxiliary, genuflect, pedantic, dragoon.

I do not think that the second and third have anything to do with Latin (Turkish/Arabic, Yiddish/Hebrew). The last four clearly do — my dictionary contains "auxiliator" (helper), "genu" (knee) + "flecto" (flex), "draco" (dragon). This seems unusual to me; I feel that most weeks have an even higher percentage of Latin (see what you think).

The word "pedantic" is an interesting example too. It is not found in this Latin dictionary per se, but it highlights another fascinating aspect of our own language. What does have an entry is paedagogus. This is a bona fide Latin word, just like "pedantic" is an English one. But it is really Greek — "παιδαγωγός". The Romans, who often employed/enslaved Greeks as tutors, borrowed the word pretty much intact. Cassell’s entry defines it as "a slave who accompanied children to and from school and had charge of them at home". That tumbled around through Europe until it got to English in several forms including "pedantic".

That does highlight another deep insight reading this particular dictionary offered: Greek! The Romans liked Greek in the same way Germans like English. They used it all the time! After reading this dictionary, I feel like I can now read Greek words in the Greek alphabet pretty well (my engineering degree — another arduous educational experience — didn’t hurt either). I certainly got an appreciation for how much Greek is in Latin and now in English.

latin266.jpg

There is a reason that despite the fact that my grandmother quit school to work in Leicester’s sock factory at the age of 14, she was actually taught a decent amount of both Latin and Greek. It wasn’t to decode ancient texts but rather to be more exact and expressive with her own native language. Reading a dictionary’s worth of Latin affirms this. Every page was like a month of reading M-W’s Word-Of-The-Day. Every page contained at least one entry where I was amazed by some bit of linguistic trivia. Often it was a deeper understanding of the intricacies of Latin itself which I thought I knew (e.g. "nemo" is nobody, but really is a contraction of "non homo" or "no man"). But mostly I was fascinated at the connection to modern English. For example, the word "schola" (originally from Greek "σχολη") is interestingly defined as "leisure, rest from work; hence learned leisure, learned conversation, debate, dispute, lecture, dissertation." Basically it’s a place where people idly hang out and talk about doing nerdy things like reading a translation dictionary of an ancient language. We have blogs for that kind of thing now!

latin410.jpg

Take a look at these sample pages and see for yourself how much is quite familiar to English speakers.

Round And Round - Round Two

2024-03-14 16:05

If you saw my recent post about rounding I came to the conclusion that the whole topic was very complicated and we should trust that the nerds who create this foundational stuff know what they’re doing and try not to worry about it.

Well, I did my best to not worry about it but after some feedback from my very observant friend Dr. S, I realized that my efforts to not worry about it were not going to hold up. You see, the problem that was brought to my attention was something I had kind of noticed. But I was trying to trust the creators of Python (and C, etc.) and assume they knew how to not let everybody down. But when it was pointed out by someone else, well, yes, my story made no sense.

Basically I was trying to demonstrate that Python does not use a round up strategy to handle values half way between candidate rounded values. Rounding to the higher value was what I was taught in school a young kid. Python documentation hints that it likes to round to even values. Perhaps that’s true when rounding to whole integers. But the examples I chose did not reflect that. I have edited one of the values in that post so that the story makes some sense, but let’s revisit the original flawed values and understand what is really going on and why it could be more important than I first thought.

Here’s the Python version of my previous example.

>>> round(5.775,2); round(5.475,2)
5.78
5.47

Ok, the 5.775 would round up to the $5.78 since 8 is the even possibility. But what about 5.475? I have come to appreciate that the round to even rule is perfectly sensible, and if was in effect wouldn’t we expect to see 5.475 round to $5.48 since again the 8 is even? But it rounds down to the 7. I did kind of notice this but was gaslighted into hazily thinking it must be the preceding digit somehow. Well, that is of course nonsense. This example is simply not following any rule that I’ve discussed. I actually think it is not really following any rounding (tie breaking) rule at all!

After experimenting with rounding well beyond what I was hoping to spend my time on, I never could discern any kind of heuristic that would allow one to predict the outcome. And that is weird. What I’m saying is that a simple sales receipt tax calculation will not be something you can properly predict and that was deeply surprising to me.

But it’s a computer; surely there is some determinism! Surely there is a reason it does what it does. After reading part one some people did have the vague idea this had to do with encoding floating point numbers as binary sequences. Those people were 100% right. I have to say that I was surprised because while I’m quite familiar with the massive can of worms involved in this topic (e.g. IEEE 754) I didn’t think it would apply to the (e.g. dollars and cents) accuracies I was interested in. But that thinking seems to be strangely wrong and naive. Even if the ability to represent (the least accurate type of) floating point numbers is inherently cursed to have some error of say, 3 parts per billion, what does that have to do with pennies in a dollar? Amazingly it matters, and pretty much always.

I wanted a very close look at how float numbers are actually used in C (Python and all the rest seem related). Let’s consider the two numbers 0.513245 and 0.513255. If I want those six digit numbers to start as exactly those values and I then would like them to later be made into 5 digit numbers with rounding, what would be done?

If you’re using the grade school algorithm of always round up when there is a tie, you get this.

0.513245 --> 0.51325
0.513255 --> 0.51326

That’s the easy way to think about it. What if we want to use the round to even heuristic? We should get this.

0.513245 --> 0.51324  (round down because final 4 is even)
0.513255 --> 0.51326  (round up because final 6 is even)

That is not what I observed. It turns out that this explanation does not help us understand anything! What really is happening?

With some helpful help from my robot friends I wrote a C program that really dissects the process by iterating over (some limited range) of all the values of floating point numbers that are possible. I’m basically incrementing my target number by the machine epsilon which is (something like) the smallest value difference that a computer can discern when representing floating point numbers.

Take a look at this table which I explain in detail below.

0.513245 - 0.51324 - 0.513244509696960449218750000000 - 00111111000000110110001111111110
0.513245 - 0.51324 - 0.513244569301605224609375000000 - 00111111000000110110001111111111
0.513245 - 0.51324 - 0.513244628906250000000000000000 - 00111111000000110110010000000000
0.513245 - 0.51324 - 0.513244688510894775390625000000 - 00111111000000110110010000000001
0.513245 - 0.51324 - 0.513244748115539550781250000000 - 00111111000000110110010000000010
0.513245 - 0.51324 - 0.513244807720184326171875000000 - 00111111000000110110010000000011
0.513245 - 0.51324 - 0.513244867324829101562500000000 - 00111111000000110110010000000100
0.513245 - 0.51324 - 0.513244926929473876953125000000 - 00111111000000110110010000000101
0.513245 - 0.51324 - 0.513244986534118652343750000000 - 00111111000000110110010000000110
0.513245 - 0.51325 - 0.513245046138763427734375000000 - 00111111000000110110010000000111
0.513245 - 0.51325 - 0.513245105743408203125000000000 - 00111111000000110110010000001000
0.513245 - 0.51325 - 0.513245165348052978515625000000 - 00111111000000110110010000001001
0.513245 - 0.51325 - 0.513245224952697753906250000000 - 00111111000000110110010000001010
0.513245 - 0.51325 - 0.513245284557342529296875000000 - 00111111000000110110010000001011
0.513245 - 0.51325 - 0.513245344161987304687500000000 - 00111111000000110110010000001100
0.513245 - 0.51325 - 0.513245403766632080078125000000 - 00111111000000110110010000001101
0.513245 - 0.51325 - 0.513245463371276855468750000000 - 00111111000000110110010000001110

0.513255 - 0.51325 - 0.513254523277282714843750000000 - 00111111000000110110010010100110
0.513255 - 0.51325 - 0.513254582881927490234375000000 - 00111111000000110110010010100111
0.513255 - 0.51325 - 0.513254642486572265625000000000 - 00111111000000110110010010101000
0.513255 - 0.51325 - 0.513254702091217041015625000000 - 00111111000000110110010010101001
0.513255 - 0.51325 - 0.513254761695861816406250000000 - 00111111000000110110010010101010
0.513255 - 0.51325 - 0.513254821300506591796875000000 - 00111111000000110110010010101011
0.513255 - 0.51325 - 0.513254880905151367187500000000 - 00111111000000110110010010101100
0.513255 - 0.51325 - 0.513254940509796142578125000000 - 00111111000000110110010010101101
0.513255 - 0.51326 - 0.513255000114440917968750000000 - 00111111000000110110010010101110
0.513255 - 0.51326 - 0.513255059719085693359375000000 - 00111111000000110110010010101111
0.513255 - 0.51326 - 0.513255119323730468750000000000 - 00111111000000110110010010110000
0.513255 - 0.51326 - 0.513255178928375244140625000000 - 00111111000000110110010010110001
0.513255 - 0.51326 - 0.513255238533020019531250000000 - 00111111000000110110010010110010
0.513255 - 0.51326 - 0.513255298137664794921875000000 - 00111111000000110110010010110011
0.513255 - 0.51326 - 0.513255357742309570312500000000 - 00111111000000110110010010110100
0.513255 - 0.51326 - 0.513255417346954345703125000000 - 00111111000000110110010010110101
0.513255 - 0.51326 - 0.513255476951599121093750000000 - 00111111000000110110010010110110

Column one is the target number I’m interested in, the perfect value I want the computer to keep track of. Column two is that exact same number as filtered through a standard C style %.5f rounding filter used by printf — in other words, C’s normal attempt to round the input value down by one digit. Now it gets interesting. The third column is what the value looks like to C as a human number when I ask it to show me all of its cards. I want to know all that it knows about what it thinks this number is. This is done by asking for 30 decimal places with %.30f. And you can see that there is all kinds of clutter there! Those are artifacts — necessary compromises — related to encoding human numbers in a computer. The trailing zeros tell us I have shown all of what it knows. Ok, if the actual digits out to 25 places are kind of gibberish, how exactly did they get that way? The answer to that is how they were encoded using 1s and 0s. Column four shows the exact binary value that encodes this number. If you kind of know how counting in binary numbers work, you can verify that I must have picked a machine epsilon that was pretty close allowing us to review a slice of the sequence of every binary number possible.

Remember I am interested in 0.513245 and 0.513255 but those were not the input. I hunted those out of the results of all of the possible (six digit) numbers with grep. These values are completely typical. What this shows us is that for each of those numbers I have discovered 17 different ways that they could be encoded. It is important to note that none of the binary encodings perfectly match our target numbers. The closest that binary numbers can achieve is around the middle of each list and it is exactly there that you can see the second column making the switch from rounding down on 5 values, to rounding up on 5 values.

This brings up a very good question — which of these binary encodings will the system choose for our target number of 0.513255? The closest two candidates are repeated below.

0.513255 - 0.51325 - 0.513254940509796142578125000000 - 00111111000000110110010010101101
0.513255 - 0.51326 - 0.513255000114440917968750000000 - 00111111000000110110010010101110

It turns out that the answer to this question makes the decision to whether the system rounds up or rounds down.

0.513255 - 0.51325 - 0.51325-->4940509796142578125000000<-- Less than 5, rounds down
0.513255 - 0.51326 - 0.51325-->5000114440917968750000000<-- Greater than 5, rounds up

Ok, maybe you’re following along, maybe not, but the question remains, how can we predict the behavior of all these rounding systems on floating point numbers?

As far as I can tell, the answer is it is not possible to predict floating point behavior. Not for programmers. Obviously it’s going to be complicated, but it’s probably worse than you think. For example, if you ask your robot friends to explain "how (gcc) compiler optimizations can affect floating point accuracy" — oh boy! It’s ugly! (Reordering operations, vectorization for SIMD, FMA — Fused Multiply Add, etc…)

The Python documentation does have a "note" that warns, "The behavior of round() for floats can be surprising…" I feel that’s somewhat of an error of omission. I feel like it would be more correct to say "the behavior of round() for floats is essentially a pseudo random number generator".

All my programming career I just figured that this was in the nether realms of part per billion accuracies I don’t care about. It’s not every day I have to, for example, work in meter accuracies all the way to Mars. But what this investigation has taught me is that floating point numbers really can be poison. My extremely simple example of calculating sales tax is something most humans can understand, but I sure underestimated how hard it would be to get a computer to properly understand it.

If you do ever need to write software that gets simple things like sales tax right, check out Python’s standard decimal module which provides a numeric type which is superior to float when struggling with these issues.

Now that I’ve learned more than I wanted to know about computer rounding, I’m going to go back to not thinking about it too much. The whole reason this came up is that I have just added a round function to my programming language (by simply borrowing Python’s) and now at least I know what to expect out of it.

I still am tempted to write another rounding function which I have traditionally used manually. I call it athlete rounding and it basically rounds up if it’s speed (kph) and down if the value is a time/distance pace (min/mile). But no, no, I will learn to make peace with Python and C’s random rounding behavior.

For reference, here’s the C program I used to generate those bit representations.

/* bits.c - Demonstration of C's float encoding system. */
#include <stdio.h>
void printBits(size_t const size, void const * const ptr) {
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i,j;
    for (i=size-1;i>=0;i--) {
        for (j=7;j>=0;j--) {
            byte= (b[i] >> j) & 1;
            printf("%u", byte);
        }
    }
}

int main() {
    float E= 3e-8; // Epsilon.
    for (float x=0.5;x<1;x+=E){
        printf("%f - %.5f - %.30f - ",x,x);
        printBits(sizeof(x), &x);
        printf("\n");
    }
    return 0;
}

Round And Round

2024-03-12 10:51

I’m no mathematician but I like to think I could comfortably score well on a third grade math test. And I would assume that my proficiency on grade school tests would transfer to the exact same applied problems as they arose in the real world. Today I was surprised to find this was not entirely true!

The topic is rounding numbers, something that is generally taught to eight year old kids. Let’s belabor the topic with a couple of examples.

Imagine you buy a $77.00 thing and the sales tax in is 7.5% — how much will you pay in sales tax? Go ahead and trust me that the precise answer when calculating 77 times 0.075 is 5.775. But that’s not how American money works and we must round. The grade school test question then is how many dollars and cents is shown on a sales receipt for this tax?

If you said $5.78, congratulations, you would ace a kid’s math test!

Let’s try another one. A different item is $211.00 — now how much is the sales tax? You can again accept that the precise answer is 15.825 which again needs to be rounded. What is the dollars and cents value printed on the receipt for this tax?

If you said $15.83, congratulations, you would ace a kid’s math test! Unfortunately, in some situations, you could be wrong!

If I have purchased a $211.00 item I can now very easily imagine that the receipt would show a 7.5% sales tax as $15.82.

First let me prove that there is a good reason to believe that the values would come out like this on a receipt. Receipts are created by software these days and most software is derived from other software that ultimately derives from something compiled by a C compiler. Consider this very simple C program.

/* rounder.c - Demonstration of C's rounding behavior. */
#include <stdio.h>
int main() {
    float num1= 5.775, num2= 15.825;
    printf("%f: %.2f\n",num1,num1);
    printf("%f: %.2f\n",num2,num2);
    return 0;
}

I’m just assigning the two values I mentioned and printing them out at the correct number of decimals. If I compile and run that, look what we get.

$ gcc -o round rounder.c && ./round
5.775000: 5.78
15.825000: 15.82

Awk is closely related to C and predictably follows.

$ echo 5.775 15.825 | awk '{printf "%.2f %.2f\n",$1,$2}'
5.78 15.82

What about Bash? You can type this right into any terminal.

$ printf "%.2f %.2f\n" 5.775 15.825
5.78 15.82

I’m guessing they probably all use a common library somehow.

What about Python? That’s actually where I first noticed this and it has this behavior too.

>>> round(5.775,2); round(15.825,2)
5.78
15.82

So this is clearly no quirk. For some reason all of these pretty serious computational systems seem to think that what you learned as a kid is not quite right. What I learned as a kid is that a value like 5.475 would be rounded up to 5.48, not down to 5.47. The rule I learned was if you are rounding and need to make a decision on a 5 you go up. In fact as a kid I learned an algorithm for programming purposes. Here it is in Applesoft BASIC as I remember it on my Apple ][+.

PRINT INT(5.775*100+.5)/100

Basically, multiply the number by 100, add .5 (letting that carry), chop off all the decimal part with the INT, and divide by 100 again to put it back into the correct scale. I have spent 40 years thinking this is how rounding works.

Here’s LibreOffice correctly imitating Excel, but it is somewhat interesting that at least in this example, it does not match the behavior of C and Python.

round-libreoffice.png

What is going on here? When I learned about rounding as a kid it would have been impossible for me and even my teachers to really learn much more about it. But today, of course there is an astonishingly rich Wikipedia page on the topic of rounding numbers.

It alerts me to the idea of "round to even". The official documentation for the Python round() function goes on to hint that is indeed the algorithm that is being used. It says.

…if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).

Note how this handles the weirdness of rounding negative numbers. I was taught that 24.5 rounded to 25 (rounding up) and -24.5 rounds to -24 (also rounding up in value). In Python (and similar) 24.5 rounds to 24 and -24.5 rounds to -24.

If you look over that Wikipedia page, you’ll start to realize that rounding is much more nuanced than your third grade teacher made it seem. I’m realizing that it is like date/time issues where armies of very smart programmers — many of whom are mathematicians! — pull their hair out over the fussiest of details.

xkcd 2867

Best to just let them get on with it and if you see some receipt that doesn’t seem to be rounded "correctly", well, it probably is!

UPDATE 2024-03-14 Or… Maybe not… At least not the "correctly" you were expecting. I just wrote a followup about this topic here.

--------------------------

For older posts and RSS feed see the blog archives.
Chris X Edwards © 1999-2024