Exploring the generic math interfaces and fixed-point arithmetic in .NET

Oliver Brown
— This upcoming video may not be available to view yet.

In .NET 7 (previewed in .NET 6) a series of new interfaces were introduced to make work with mathematical operations easier.

.NET has had generics almost forever allowing you to write algorithms that work with many different types, but this hasn’t been possible for basic maths until this was introduced.

The main reason this has been done now is for machine learning and AI implementations where the classic computing tradeoff of speed vs. space appears - if you’re dealing with very large arrays of numbers, maybe you want to switch from a 64 bit double to 32 bit float (or even the newly introduced 16 bit half).

The in-progress implementation of my expanded Elo rating system is based on this for that reason.

Fixed-point arithmetic

There is another reason to use the interfaces though - perhaps you want a completely different implementation of the basic mathematical operations. One example would be fixed-point arithmetic instead of floating-point arithmetic.

The biggest reason to do this is because floating-point arithmetic is not, in practice, deterministic.

More about floating-point arithmetic determinism

This is a subtle topic. Any specific IEE 754 floating point operation is deterministic for the same inputs. But those inputs include various settings that might change unexpectedly, and things like reordering of operations will give you different results due to rounding.

And it is even worse in .NET (ironically) because of its portable nature. Your code could be JIT compiled completely out of your control on many different processor architectures.

Here are some more resources about it:

There have been a few implementations of fixed-point arithmetic in .NET:

That last one is fairly recent (it targets .NET 6) and is MIT licensed, so I decided to see if I could modify it to support the generic math interfaces.

GamesWithGravitas.FixMath

The (still in-progress) result is available here in GitHub.

It takes the F32 and F64 types from FixPointCS and implements the following interfaces:

  • INumber
  • IBinaryNumber
  • ISignedNumber
  • IRootFunctions
  • ITrigonometricFunction

Most of the work is forwarding to the existing implementations. Some of the things that I had to actually write code for:

Formatting and parsing

There are a bunch of methods relating to converting to and from strings. My implementation uses double as an intermediate type. I guess these have the chance to not be deterministic but for the things I’d use it for it would not matter.

TryConvertFrom… and TryConvertTo…

These methods are used to convert between these types and others. They come in three versions: Checked, Truncating and Saturating. I have currently implemented all three to do the same thing.

Mapominoes - or learning to hate islands even more than when playing Plague Inc.

Oliver Brown
— This upcoming video may not be available to view yet.
As an Amazon Associate I earn from qualifying purchases. See here for more information.

A while ago I bought Mapominoes Europe on a whim, and I’m now having to fight the urge to buy its many variations/expansions.

As the title suggests it is broadly based on dominoes, but instead of placing tiles by the numbers they have in common, it is based on countries with shared borders. Also unlike dominoes the cards are played not in a line but in a grid, and all neighbours have to be compatible.

The mechanics are simple enough to pick up and the game is quite suitable for children - I’m having fun playing with my six year old. It does hide some surprising depth though.

All the cards are dealt between the players and the goal is to be the first to play all your cards. Every player also starts with a pair of transit cards which can be played as stand-ins for either a sea (which are listed on the cards just like countries) or as another country. You get an extra turn if you can play a card bordering more than one card, and miss a turn if you are forced to draw another transit card because you can’t go.

There are several versions of the game, some of which are compatible with each other and can be combined into a larger game. The compatibles ones are:

A finished game of Europe and Asia & Australasia

There are also two standalone games:

After getting the Europe set I also got the Asia & Australasia set. Despite it taking up a lot of space, playing with those two was a lot of fun. Trying to play game with more than two would be challenging I think (although specifically in the case of those two it is helped by both sets containing Russia and Turkey).

Elo rating for ad hoc teams

Oliver Brown
— This upcoming video may not be available to view yet.

One final feature my expanded Elo rating needs (or at least the last I can think of) is the ability to deal with ad hoc teams.

By “ad hoc teams”, I mean teams of individual players with their own ratings that are on the same team for a specific game, but don’t generally stay as a team (established teams that always play together should be treated as their own “players” with their own rating).

This is not a common requirement, but the specific use case I had was an office ping pong table. Some times people would play singles and some times they would play doubles, but with no really established teams.

Necessary features

Firstly, the two key ratings operations need to work:

  • Estimate the result of an unplayed game
  • Updating ratings after an actual result

And all the existing features should be supported:

  • Two or more teams
  • Unfair games
  • Ties

Additionally, it should support teams of arbitrary (and mixed) sizes, including teams of size one. This brings us to one of our first less-obvious requirements - since this is expanding an existing system, it should be compatible with the existing system where it overlaps. So the following additional requirement makes sense:

  • Teams of one should give the same result as just using individuals

Simple solution

Just like with unfair games in which an adjusted rating is calculated first, and then used in the rest of the algorithm, and adjusted rating should be calculated for a team. This would trivially allow all the existing features to just work.

The most obvious way to calculate such a rating would be a simple arithmetic mean of all the players. This would definitely support our key requirement, but would it produce meaningful results?

At this point I think simplicity has to win out over sophistication. The most general solution would allow players to be weighted on each team (perhaps different roles in a team have different impacts on the result) but I think those situations are more likely to be handled with a per team rating.

Stargate viewing order

Oliver Brown
— This upcoming video may not be available to view yet.

There is a Stargate movie, three TV series’ and some feature length specials. It is not necessarily obvious what order to watch them in. There is a suggested order available on several websites, but they are usually hard to read because of ads.

This is just a table designed to be easy to read.

The strategy for handling the overlapping seasons of SG-1 and Atlantis is to alternate episodes, while keeping two-part episodes together.

Series Episode Title
Movie Stargate
SG-1 1x01 Children of the Gods, Part 1
SG-1 1x02 Children of the Gods, Part 2
SG-1 1x03 The Enemy Within
SG-1 1x04 Emancipation
SG-1 1x05 The Broca Divide
SG-1 1x06 The First Commandment
SG-1 1x07 Cold Lazarus
SG-1 1x08 The Nox
SG-1 1x09 Brief Candle
SG-1 1x10 Thor’s Hammer
SG-1 1x11 The Torment of Tantalus
SG-1 1x12 Bloodlines
SG-1 1x13 Fire and Water
SG-1 1x14 Hathor
SG-1 1x15 Singularity
SG-1 1x16 Cor-ai
SG-1 1x17 Enigma
SG-1 1x18 Solitudes
SG-1 1x19 Tin Man
SG-1 1x20 There But For the Grace of God
SG-1 1x21 Politics
SG-1 1x22 Within the Serpent’s Grasp
Series Episode Title
SG-1 2x01 The Serpent’s Lair
SG-1 2x02 In the Line of Duty
SG-1 2x03 Prisoners
SG-1 2x04 The Gamekeeper
SG-1 2x05 Need
SG-1 2x06 Thor’s Chariot
SG-1 2x07 Message in a Bottle
SG-1 2x08 Family
SG-1 2x09 Secrets
SG-1 2x10 Bane
SG-1 2x11 The Tok’ra, Part 1
SG-1 2x12 The Tok’ra, Part 2
SG-1 2x13 Spirits
SG-1 2x14 Touchstone
SG-1 2x15 The Fifth Race
SG-1 2x16 A Matter of Time
SG-1 2x17 Holiday
SG-1 2x18 Serpent’s Song
SG-1 2x19 One False Step
SG-1 2x20 Show and Tell
SG-1 2x21 1969
SG-1 2x22 Out of Mind
Series Episode Title
SG-1 3x01 Into the Fire
SG-1 3x02 Seth
SG-1 3x03 Fair Game
SG-1 3x04 Legacy
SG-1 3x05 Learning Curve
SG-1 3x06 Point of View
SG-1 3x07 Deadman Switch
SG-1 3x08 Demons
SG-1 3x09 Rules of Engagement
SG-1 3x10 Forever in a Day
SG-1 3x11 Past and Present
SG-1 3x12 Jolinar’s Memories
SG-1 3x13 The Devil You Know
SG-1 3x14 Foothold
SG-1 3x15 Pretense
SG-1 3x16 Urgo
SG-1 3x17 A Hundred Days
SG-1 3x18 Shades of Grey
SG-1 3x19 New Ground
SG-1 3x20 Maternal Instinct
SG-1 3x21 Crystal Skull
SG-1 3x22 Nemesis
Series Episode Title
SG-1 4x01 Small Victories
SG-1 4x02 The Other Side
SG-1 4x03 Upgrades
SG-1 4x04 Crossroads
SG-1 4x05 Divide and Conquer
SG-1 4x06 Window of Opportunity
SG-1 4x07 Watergate
SG-1 4x08 The First Ones
SG-1 4x09 Scorched Earth
SG-1 4x10 Beneath the Surface
SG-1 4x11 Point of No Return
SG-1 4x12 Tangent
SG-1 4x13 The Curse
SG-1 4x14 The Serpent’s Venom
SG-1 4x15 Chain Reaction
SG-1 4x16 2010
SG-1 4x17 Absolute Power
SG-1 4x18 The Light
SG-1 4x19 Prodigy
SG-1 4x20 Entity
SG-1 4x21 Double Jeopardy
SG-1 4x22 Exodus
Series Episode Title
SG-1 5x01 Enemies
SG-1 5x02 Threshold
SG-1 5x03 Ascension
SG-1 5x04 The Fifth Man
SG-1 5x05 Red Sky
SG-1 5x06 Rite of Passage
SG-1 5x07 Beast of Burden
SG-1 5x08 The Tomb
SG-1 5x09 Between Two Fires
SG-1 5x10 2001
SG-1 5x11 Desperate Measures
SG-1 5x12 Wormhole X-treme!
SG-1 5x13 Proving Ground
SG-1 5x14 48 Hours
SG-1 5x15 Summit
SG-1 5x16 Last Stand
SG-1 5x17 Fail Safe
SG-1 5x18 The Warrior
SG-1 5x19 Menace
SG-1 5x20 The Sentinel
SG-1 5x21 Meridian
SG-1 5x22 Revelations
Series Episode Title
SG-1 6x01 Redemption, Part 1
SG-1 6x02 Redemption, Part 2
SG-1 6x03 Descent
SG-1 6x04 Frozen
SG-1 6x05 Nightwalkers
SG-1 6x06 Abyss
SG-1 6x07 Shadow Play
SG-1 6x08 The Other Guys
SG-1 6x09 Allegiance
SG-1 6x10 Cure
SG-1 6x11 Prometheus
SG-1 6x12 Unnatural Selection
SG-1 6x13 Sight Unseen
SG-1 6x14 Smoke & Mirrors
SG-1 6x15 Paradise Lost
SG-1 6x16 Metamorphosis
SG-1 6x17 Disclosure
SG-1 6x18 Forsaken
SG-1 6x19 The Changeling
SG-1 6x20 Memento
SG-1 6x21 Prophecy
SG-1 6x22 Full Circle
Series Episode Title
SG-1 7x01 Fallen
SG-1 7x02 Homecoming
SG-1 7x03 Fragile Balance
SG-1 7x04 Orpheus
SG-1 7x05 Revisions
SG-1 7x06 Lifeboat
SG-1 7x07 Enemy Mine
SG-1 7x08 Space Race
SG-1 7x09 Avenger 2.0
SG-1 7x10 Birthright
SG-1 7x11 Evolution, Part 1
SG-1 7x12 Evolution, Part 2
SG-1 7x13 Grace
SG-1 7x14 Fallout
SG-1 7x15 Chimera
SG-1 7x16 Death Knell
SG-1 7x17 Heroes, Part 1
SG-1 7x18 Heroes, Part 2
SG-1 7x19 Resurrection
SG-1 7x20 Inauguration
SG-1 7x21 Lost City, Part 1
SG-1 7x22 Lost City, Part 2
Series Episode Title
SG-1 8x01 New Order, Part 1
SG-1 8x02 New Order, Part 2
Atlantis 1x01 Rising, Part 1
Atlantis 1x02 Rising, Part 2
SG-1 8x03 Lockdown
Atlantis 1x03 Hide and Seek
SG-1 8x04 Zero Hour
Atlantis 1x04 Thirty-Eight Minutes
SG-1 8x05 Icon
Atlantis 1x05 Suspicion
SG-1 8x06 Avatar
Atlantis 1x06 Childhood’s End
SG-1 8x07 Affinity
Atlantis 1x07 Poisoning the Well
SG-1 8x08 Covenant
Atlantis 1x08 Underground
SG-1 8x09 Sacrifices
Atlantis 1x09 Home
SG-1 8x10 Endgame
Atlantis 1x10 The Storm
Atlantis 1x11 The Eye
SG-1 8x11 Gemini
SG-1 8x12 Prometheus Unbound
Atlantis 1x12 The Defiant One
SG-1 8x13 It’s Good to Be King
Atlantis 1x13 Hot Zone
SG-1 8x14 Full Alert
Atlantis 1x14 Before I Sleep
SG-1 8x15 Citizen Joe
Atlantis 1x15 Sanctuary
SG-1 8x16 Reckoning, Part 1
SG-1 8x17 Reckoning, Part 2
Atlantis 1x16 The Brotherhood
Atlantis 1x17 Letters from Pegasus
SG-1 8x18 Threads
Atlantis 1x18 The Gift
SG-1 8x19 Moebius, Part 1
SG-1 8x20 Moebius, Part 2
Atlantis 1x19 The Siege, Part 1
Atlantis 1x20 The Siege, Part 2
Series Episode Title
Atlantis 2x01 The Siege, Part 3
SG-1 9x01 Avalon, Part 1
SG-1 9x02 Avalon, Part 2
Atlantis 2x02 The Intruder
SG-1 9x03 Origin
Atlantis 2x03 Runner
SG-1 9x04 The Ties That Bind
Atlantis 2x04 Duet
SG-1 9x05 The Powers That Be
Atlantis 2x05 Condemned
SG-1 9x06 Beachhead
Atlantis 2x06 Trinity
SG-1 9x07 Ex Deus Machina
Atlantis 2x07 Instinct
SG-1 9x08 Babylon
Atlantis 2x08 Conversion
SG-1 9x09 Prototype
Atlantis 2x09 Aurora
SG-1 9x10 The Fourth Horseman, Part 1
SG-1 9x11 The Fourth Horseman, Part 2
Atlantis 2x10 The Lost Boys
Atlantis 2x11 The Hive
SG-1 9x12 Collateral Damage
Atlantis 2x12 Epiphany
SG-1 9x13 Ripple Effect
Atlantis 2x13 Critical Mass
SG-1 9x14 Stronghold
Atlantis 2x14 Grace Under Pressure
SG-1 9x15 Ethon
Atlantis 2x15 The Tower
SG-1 9x16 Off the Grid
Atlantis 2x16 The Long Goodbye
SG-1 9x17 The Scourge
Atlantis 2x17 Coup D’etat
SG-1 9x18 Arthur’s Mantle
Atlantis 2x18 Michael
SG-1 9x19 Crusade
Atlantis 2x19 Inferno
SG-1 9x20 Camelot
Atlantis 2x20 Allies
Series Episode Title
Atlantis 3x01 No Man’s Land
Atlantis 3x02 Misbegotten
SG-1 10x01 Flesh and Blood
SG-1 10x02 Morpheus
Atlantis 3x03 Irresistible
SG-1 10x03 The Pegasus Project
Atlantis 3x04 Sateda
SG-1 10x04 Insiders
Atlantis 3x05 Progeny
Atlantis 3x06 The Real World
SG-1 10x05 Uninvited
SG-1 10x06 200
Atlantis 3x07 Common Ground
SG-1 10x07 Counterstrike
Atlantis 3x08 McKay and Mrs. Miller
SG-1 10x08 Memento Mori
Atlantis 3x09 Phantoms
SG-1 10x09 Company of Thieves
Atlantis 3x10 The Return, Part 1
Atlantis 3x11 The Return, Part 2
SG-1 10x10 The Quest, Part 1
SG-1 10x11 The Quest, Part 2
Atlantis 3x12 Echoes
SG-1 10x12 Line in the Sand
Atlantis 3x13 Irresponsible
SG-1 10x13 The Road Not Taken
Atlantis 3x14 Tao of Rodney
SG-1 10x14 The Shroud
Atlantis 3x15 The Game
SG-1 10x15 Bounty
Atlantis 3x16 The Ark
SG-1 10x16 Bad Guys
Atlantis 3x17 Sunday
SG-1 10x17 Talion
Atlantis 3x18 Submersion
SG-1 10x18 Family Ties
Atlantis 3x19 Vengeance
SG-1 10x19 Dominion
Atlantis 3x20 First Strike
SG-1 10x20 Unending
Feature length The Ark of Truth
Series Episode Title
Atlantis 4x01 Adrift
Atlantis 4x02 Lifeline
Atlantis 4x03 Reunion
Atlantis 4x04 Doppelganger
Atlantis 4x05 Travelers
Atlantis 4x06 Tabula Rasa
Atlantis 4x07 Missing
Atlantis 4x08 The Seer
Atlantis 4x09 Miller’s Crossing
Atlantis 4x10 This Mortal Coil
Atlantis 4x11 Be All My Sins Remember’d
Atlantis 4x12 Spoils of War
Atlantis 4x13 Quarantine
Atlantis 4x14 Harmony
Atlantis 4x15 Outcast
Atlantis 4x16 Trio
Atlantis 4x17 Midway
Atlantis 4x18 The Kindred, Part 1
Atlantis 4x19 The Kindred, Part 2
Atlantis 4x20 The Last Man
Series Episode Title
Atlantis 5x01 Search and Rescue
Feature length Continuum
Atlantis 5x02 The Seed
Atlantis 5x03 Search and Rescue
Atlantis 5x04 Broken Ties
Atlantis 5x05 The Seed
Atlantis 5x06 The Daedalus Variations
Atlantis 5x07 Ghost in the Machine
Atlantis 5x08 The Shrine
Atlantis 5x09 Whispers
Atlantis 5x10 The Queen
Atlantis 5x11 Tracker
Atlantis 5x12 First Contact
Atlantis 5x13 The Lost Tribe
Atlantis 5x14 Outsiders
Atlantis 5x15 Inquisition
Atlantis 5x16 The Prodigal
Atlantis 5x17 Remnants
Atlantis 5x18 Brain Storm
Atlantis 5x19 Infection
Atlantis 5x20 Identity
Atlantis 5x21 Vegas
Atlantis 5x22 Enemy at the Gate
Series Episode Title
Universe 1x01 Air, Part 1
Universe 1x02 Air, Part 2
Universe 1x03 Air, Part 3
Universe 1x04 Darkness
Universe 1x05 Light
Universe 1x06 Water
Universe 1x07 Earth
Universe 1x08 Time
Universe 1x09 Life
Universe 1x10 Justice
Universe 1x11 Space
Universe 1x12 Divided
Universe 1x13 Faith
Universe 1x14 Human
Universe 1x15 Lost
Universe 1x16 Sabotage
Universe 1x17 Pain
Universe 1x18 Subversion
Universe 1x19 Incursion, Part 1
Universe 1x20 Incursion, Part 2
Series Episode Title
Universe 2x01 Intervention
Universe 2x02 Aftermath
Universe 2x03 Awakening
Universe 2x04 Pathogen
Universe 2x05 Cloverdale
Universe 2x06 Trial and Error
Universe 2x07 The Greater Good
Universe 2x08 Malice
Universe 2x09 Visitation
Universe 2x10 Resurgence
Universe 2x11 Deliverance
Universe 2x12 Twin Destinies
Universe 2x13 Alliances
Universe 2x14 Hope
Universe 2x15 Seizure
Universe 2x16 The Hunt
Universe 2x17 Common Descent
Universe 2x18 Epilogue
Universe 2x19 Blockade
Universe 2x20 Gauntlet
Feature length Stargate Origins: Catherine

Glom of nit

Oliver Brown
— This upcoming video may not be available to view yet.
As an Amazon Associate I earn from qualifying purchases. See here for more information.

I have four blogs running the same theme that each feature a letter as the favicon. I hoped they would spell out a word.

glom

This is of course the motto of the Ankh-Morpork Post Office.

Neither rain nor snow nor gl om of ni t can stay these mes engers abo t their duty.

If you’d like to more consider Going Postal by Terry Pratchett.

Importing old posts from my first blog

Oliver Brown
— This upcoming video may not be available to view yet.

I have now imported posts from my very first blog, which was in fact the very first content I hosted on OliverBrown.me.uk.

It is almost entirely personal content with evidence of some of my early attempts to make money online.

As with the LiveJournal content, it is available in its own section I decided to call phpdiary. I didn’t really give it a name at the time but it was implemented as a bunch plain text files for each post rendered with a PHP script called diary.php.

Somewhat awkwardly the posts did not have titles and Hugo (or at least this theme) does not work well without them. So they are titled after the date of the post (and often the time since I tended to post several times a day).

I don’t think I have any more older posts to add, so it seems this post from December 2003 will stay my oldest post, meaning I now have over 20 years of content.

Importing old posts from LiveJournal

Oliver Brown
— This upcoming video may not be available to view yet.

Before I hosted my own content in various forms, I maintained a LiveJournal which is still available at https://galaxiaguy.livejournal.com (although I warn you, when I looked at it today it was full of Russian Bitcoin related ads).

I have finally imported the missing posts from this.

There weren’t many so I just did it manually. I even went to the effort of updating my theme to include “mood” and “music” in my post front matter and it add it to theme (these were very important to LiveJournal back in the day).

The posts are all part of the normal flow (and currently start around page 56). There is a bit of duplicated content as I posted some content to both places for a few days. Either way, the imported content is available in isolation in the LiveJournal section.

One interesting consequence is I have changed the copyright start year for the blog from “2005” to 2004".

Fixing some blank posts

Oliver Brown
— This upcoming video may not be available to view yet.

My blog has been through a lot. At some point I may try and make a coherent timeline, if only for my own benefit.

Content has been migrated from platform to platform, and format to format. Some of it got broken along the way. This resulted in some of the posts just being blank. I finally went back and found them all and manually reinstated the content.

I doubt this will be of any interest to anyone except me or people who know me, but it may be nostalgic for anyone else who was doing web development in 2005.

Personally, my writing style from back then makes me uncomfortable, and it is not helped by the fact I’ve left some of my spelling errors intact.

Date Post
2005-04-14 It’s-a me!
2005-04-15 Reborn progress
2005-04-19 Exams soon…
2005-04-22 Should Galaxia use Ajax?
2005-04-22 Upcoming features for XHTML friends
2005-04-25 Silly .htaccess
2005-04-28 Agregating me in XHTML Friends
2005-05-08 Objects
2005-05-09 XHTML Friends is now about people
2005-05-09 Things you notice
2005-05-25 Gary Lineker in bad taste?
2005-05-18 Odd PHP problem
2005-06-05 Proof of the existence of Albinaaaaaaaghs
2006-05-05 Explaining the Matrix

Added Wayback Machine links

Oliver Brown
— This upcoming video may not be available to view yet.

After realising that I’ve been blogging for nearly 19 years, and that I have lot of old content with many broken links, I decided to add support for Wayback Machine links.

The Wayback Machine (part of the Internet Archive) archives web pages for posterity, and importantly, tries to archive many versions over time.

At the bottom of each my posts is now a section that links to the archived version of the page, as of the date of the post. This will attempt to show the latest archived version of the page before that date.

In practice many pages did not get archived, or the archived version may not contain the exact content on the day I wrote the post, but it is better than nothing.

To keep this service alive (along with other activities of the Internet Archive), please consider donating.

Migrated another site from WordPress to Hugo and Azure Static Web Apps

Oliver Brown
— This upcoming video may not be available to view yet.

Some time ago I migrated my blog from WordPress (hosted on WordPress.com) to Hugo (hosted on Azure Static Web Apps). Over the past week I did the same for my wife’s blog.

The process went well. The Hugo site has pretty good docs for migrating to Hugo from various other platforms. The exact steps I took were:

  1. Export content from Wordpress.
  2. Generate Hugo content from the export using blog2md.
  3. Upload to GitHub.
  4. Create an Azure Static Web app (which as detailed before creates a build pipeline and deploys to an autogenerated Azure domain).
  5. Browse the site and fix any broken content.
  6. Add any custom functionality desired to the theme files.
  7. Update the domain to point at the Azure instance.

The new blog is available at www.luliriisi.me.uk (the original is still available at luliriisi.wordpress.com).

Sharing themes

That “custom functionality” is of course optional, and a potential rabbit hole depending on your exact needs. In the case of my wife’s blog, because she is a hand-knitting pattern designer I added some templating for sharing her patterns easily.

And, because the core theme is shared with this blog (and Games with Gravitas), that functionality is also available here - which is why I can easily add one of her patterns to this post.