Re: “a base-neutral system for naming numbering systems” from jan Misali

Despite their importance to modern mathematics, alternative numeric systems are a concept often left towards the end of standard education throughout the English-speaking world. This may be in part to their diminishing presence in the last 6⛂STK years with the introduction of the metric measurement system. However, even in current day USA, we still use the imperial measurement system, with our less standard mix of binary, trinary, quaternary, dozenal, and arbitrarily large bases. Our way of describing numbers shapes our understanding of things.
In 2018, internet personality Mitchel John “jan Misali” Halley made a numeric base naming convention that focused on factor pairs that make up a given radix. The system suffers from its searing focus on the even treatment of all bases given the very limited source of affixes representing the factors. In addition, jan Misali only targeted integer and rational radices (or more accurately: natural numbers; their opposites; and their ratios). This is not an alternative, but rather a fork of this idea. This is the Misali-Dual numeric base naming convention.

You may notice words throughout are highlighted. Moving your finger or cursor over these will reveal a brief definition of the word. This is to make this article as accessible as possible.

Natural Numbers

The foundation of our understanding of numbers, the numbers by which we can count are naturally the first any system will want to address. For our purposes, natural numbers will also include zero, though this is not the only definition. The first idea I had was the use of multiple roots as seen in medical terminology, typically Greco-Roman, but not always for reasons that will become more obvious as we work our way down the list.

Radix Root DECNamed ConsesusAbbreviationAffix-AAffix-B
0NulinaryNULnil/le-zilch/i-
1UnaryUNIun/i-hen/a-
2BinaryBINb/i-d/i-
3TrinaryTRItert/i-t/ri-
4QuaternaryQUAquandr/i-tetr/a-
5PentinaryPENquint/i-pent/a-
6SeximalSXMsex/i-hex/a-
7SeptinarySPTsept/a-hept/a-
8OctalOCTtav/o-oct/o-
9EnnibainalENNnun/o-enn/e-
10DecimalDECden/a-dec/a-
11ElenaryELEel/a-maor/i-
12DozenalDOZdoz/ena-mon/e-
13BakinaryBAKchef/a-bak/e-
14FortecimalFRTfort/e-macr/o-
15HulibainalHULhul/i-guiran/i-
16HexcodeHEXcomp/u-ord/ni-
17SubinarySUBsub/o-hup/o-
18TelimalTELadult/u-tele/i-
19FininaryFINfin/o-esch/a-
20VigesimalVIGvig/e-ikos/i-
23ErinaryERIkal/a-er/i-
24DailyDAYday- dai-emar/i-
26AlphacimalALPalph/a-gram/ma-
29LunarLUNlun/a-artem/i-
36NiftimalNFMnif/ti-dict/o-
52StakimalSTKpap/ie-stak/o-
60HourlyHRLhor/i-min/o-
65SenjobainalSNJsenj/o-ger/a-
100CentesimalCENcent/e-hect/o-
120CardiacCRDcardi/o-hem/ato-
360CircularCIRradi/o-degr/i-
1,000MilleceimalMILmill/e-kil/o-
5,040PlatonialPLTput/o-plat/o-
1,000,000LardocimalLARlard/o-lip/o-
Radix PropertySuffix
Indivisible by natural numbers less than itself-in/ary
Odd-bainal
Even-c/imal

There is a lot going on up here so let’s have a brief discussion of medical terminology, the second easiest language an English speaker can learn. When you want to describe something in medical terminology, you take all the items in question such as stomach and intestines, find their medical roots such as gastr/o- and enter/o-, and add them to a suffix to make the meaning such as -ology to make gastroenterology which is the study of the digestive tract and its function. In this same sense, we take the factors of smaller bases such as base-21DEC being the product of 3DOZ and 11SXM. This gives us the name triseptabinal. However, numbers like 31DEC belong to a category of numbers known as prime numbers. Before we can create naming conventions, we need to get into more basic arithmetic.

Rational Numbers

Natural numbers are a subset of all integers, which include the opposite of natural numbers or negative numbers and always includes zero. Integers are then a subset of all rational numbers, numbers that can be represented as an integer divided by a natural number where it is defined without zero. Similarly to before, roots are predominately represented by Greco-Roman affixes.

Arithmetic Operational RootAbbreviationAffix-AAffix-B
Addition +ADDet/a-ka/i-
Negation 0-NEGneg/a-yam/i-
Inversion ⅟nDIVinv/e-vot/i-
Exponentiation nEXPexp/a-pow/a-
Logarithm ㏒LOGlog/o-fract/o-

Without arithmetic, the creation of names of prime radices purely through factorization is impossible. Instead, we conceptualize primes as the addition of one to the number that proceeds them. This means 31DEC is simply just kaipentasexihenary, made up of roots ka/i-, pent/a-, sex/i-, hen/a-, and -in/ary or “and”, “five”, “six”, “one”, and “prime”. I didn’t want to separate the arithmetic table, so I did elect to push up discussion of all rational numbers.
Negative radices are represented as the very simple “nega” or literally negative versions of their natural numbers. Negabinary is just base-(10)BIN.
Ratio radices are a bit odd. All conventions to this point suggests the largest factor goes last. As such, we’d expect 5/10SPT to be votiseptapentinary. What about 1/35DEC? Votiseptapentinary. That is the opposite of what we want. Instead, when inverting a number, it needs to terminate the same way we do with addition. Votiseptahenaquintary is base-10/12PEN and votiseptapentunary is base-1/55SXM.
These last three operators are not useful in the rational side of numbers.

Irrational Numbers

Irrational numbers are numbers that cannot be created as the output of field operations. Pi (generally represented as lowercase Greek π) is the result of taking the circumference of a circle and dividing it by twice its radius. This number is not a ratio of two natural numbers, which is among one reason we have given it a fun name. Similarly, the sum of the series of the inverse of all factorialized natural numbers cannot be rationalized as a ratio between any less than infinite factors. Euler’s number (generally represented as italics, lowercase Latin e) also then cannot be represented in our system yet.

Irrational Radix Root DECNamed ConsensusAbbreviationAffix-AAffix-B
12√2EqualaryEQLequal/a-temp/o-
Plastic Ratio ρRhonaryPLAplast/i-pis/o-
Golden Ratio ϕPhinaryAURaur/a-khrus/o-
Supergolden Ratio ψPsinarySAUplentin/o-lefk/o-
Silver Ratio δSDhelsinaryARGargent/u-argyr/o-
Euler’s number eEulariaryEULeul/e-nat/o-
Pi πPinaryPIRp/e-p/i-

We can then create more irrational bases like natopary and powapeheneulinary. I’m not sure how they are useful, and honestly much of everything going forward makes less and less sense to me. I knew irrational radices were a thing, but I always wondered why exactly you would use them. Equalary is used in music temperament which makes sense, and psinary was used in early analog-to-digital conversion. But dhelsinary and phinary just seem to exist.

Imaginary and Complex Numbers

Imaginary numbers are this side effect of doing operations you cannot normally do, like the square-root of a negative number. Why these are useful is complicated and has a lot to do with gimbal-lock and fractals among other problems. One idea is to treat it literal, making base-i powinvanegahenunihenary which is a mouthful and not very useful. Instead, we conceptualize the idea as a whole category of what is this imaginary plane.
This is the part where the table would go if describing more than one imaginary item made sense. However, I can find little reason to create more than one row of imaginary inventory as well as an additional operation.

Imaginary iImaginaryIMGim/a-phant/ou-
Bi-operational Increment ±ASEou-eith/re-

Of note is that ± is read plus-or-minus. In cases where minus-or-plus is required, the item is negated before incrementing the operations. Is there a better name for these operations?
With both of these, we can finally make our favorite fractal, the Twindragon, into a base. -1 ± i is… Complicated question, is i further to zero than 1? They are supposedly equidistant, so we will need to make our own rules. For the sake of clarity, imaginary numbers are smaller (that is closer to zero) than negative integers, and negative integers are smaller (that is closer to zero) than natural numbers. This isn’t actually true, but rather a “we need to draw a line in the sand somewhere”. So, eithimanuyamuninulinary is base-(1) ± i and phantobinary is base-2i.

Mixed radices

For the most part, we keep the tune of the regular system. You just list it with a few notable exceptions.

Mixed Radix RootsNamed ConsensusAbbreviationAffix-AAffix-B
Primes ℙPrimorialPRIprim/o-prot/o-
Factorials n!FactorialFCTperm/u-fact/o-
Fibonacci n!FFibonorialFBNfib/o-self/i-

Shorthand Representation

I do not believe bases without naming consensus should have true abbreviations. Abbreviations are useless unless they genuinely make identification of things faster. As such, to shorthand write any base, you can tabulate the name back to their roots, take the first two letters of each abbreviation. This means the base is always identifiable, similar to chemical composition notation. This does mean the eithimanegahennulinary would become the “not-much shorter” AsImNuNeUnNu, but a novice would be able to recognize it as an imaginary or complex radix without significant effort.

Name calculation

We’ve briefly covered the dynamics of calculation. Numbers are sorted in order of distance to zero, prioritizing imaginary components over negative over positive components. But how does this function as a whole? I feel the best way to describe this is programmatically.

Gather affixes
 Search radix
 If radix has Named Consensus
  Return Named Consensus
  Exit function
 Set suffix to "-in/ary"
 Select case radix type
  Case natural number
   Find factor pairs
   If number of items of factor pairs is one
    Add affix "ADD"
    With radix one less than current
     Gather affixes
     For each affix
      Add current affix
    Add affix "UNI"
    Process affixes
    Exit Function
   For each factor pair
    If total number of Named Consensus in factor pair is greater than preference
     Set preference to current total number of Named Consensus
   Delete items in factor pairs with fewer Named Consensus than preference
   Sort factor pairs on difference of members, less to great
   Select item with smallest difference
   Sort factor pair on difference of members to zero, less to great
   For each member in factor pair
    Gather affixes
    For each affix
     Add current affix
   If modulos of radix by one plus one is one
    Set suffix to "-bainal"
   Else
    Set suffix to "-c/imal"
   Process affixes
   Exit Function
  Case rational number
   Select case nonnatural rational radix type
    Case negation
     Add affix "NEG"
     With absolute value of radix
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function
    Case inversion
     Add affix "DIV"
     With denominator
      Gather affixes
      Reverse affix order
      For each affix
       Add affix
     Add affix "UNI"
     With numerator
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function
  Case Else
   Select case operand type
    Case exponentation
     Add affix "EXP"
     With exponent
      Gather affixes
      For each affix
       Add affix
     Add affix "UNI"
     With base
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function
    Case logarithm
     Add affix "LOG"
     With antilogarithm
      Gather affixes
      For each affix
       Add affix
     Add affix "NUL"
     With base
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function
    Case factorial
     Add affix "FCT"
     With elements
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function
    Case addition
     Add affix "ADD"
     For each term
      Gather affixes
      For each affix
       Add affix
      Add affix "NUL"
     Process affixes
     Exit function
    Case bioperation increment
     Add affix "ASE"
     For each term
      Gather affixes
      For each affix
       Add affix
      Add affix "NUL"
     Process affixes
     Exit function
    Case imaginary
     Add affix "IMG"
     With coefficient
      Gather affixes
      For each affix
       Add affix
     Process affixes
     Exit function

Process affixes
 For each affix
  Search affix
  If index modulus one plus one is one
   Select item-A
  Else
   Select item-B
  If item is starts vowel sound
  or item first consonant is equal to item index one less than current last consonant
   Set item index one less than current to end to ends consonant
 If suffix is "-bainal"
  Set last item to ends vowel
 If last item last consonant not equal to suffix first consonant
  Set last item to ends vowel
  Set suffix to start syllable
 Else
  Set last item to ends consonant
  Set suffix to start vowel
 Concatenate items and suffix
 Return name
 Exit function

Stray thoughts

You may have also noticed the use of subscript letter with abbreviations instead of decimal numeric reference for written numbers. It’s far clearer to say 10DEC than 1010. Because what is 10? That’s kinda the whole point of this discussion.

Conclusion

The original draft of this from nearly six months ago included a pronunciation guide that was more unhelpful that anything else. It can be summarized as “If it feels like the correct pronunciation, then that’s right” and “Here’s how I, someone from the Midwestern USA, pronounce these things” with a lot of IPA symbols.
The original creator, jan Misali, should be proud of the word they put in, it creates a more realistic and more universally understandable system that depends less on preexisting notions that create bias. Most importantly, I see this not as a replacement, but an extension to jan Misali’s proposed system. I also see this as not complete, but another stepping-stone in number theory. One thing I would like further emphasis is counting systems as used by various world cultures. Already through this did I discover that the Huli people used a mostly undocumented base-13DOZ and the Māori people use a much more documented base-15SXM.
In my opinion, this system is at half its reasonable capacity, being capable of well accommodating 20STK named items. In theory, it could have as many 2A4HEX items, but pronounceability and distinct symbolization will become a problem.
Further on that idea, it could also make use of less common Latin characters like ẞß (Eszett), Þþ (Thorn), Ƿƿ (Wynn), Ƕƕ (Hwair), Ꞷꞷ (Omega), Ꞵꞵ (Beta), Ꜫꜫ (Tresillo), Ꜧꜧ (Heng), Ƹƹ (Ayin), Ʒʒ (Ezh), and Ȝȝ (Yogh). I would like to note that it makes the most sense to use non-diacritical glyphs that exist already in the Latin alphabet with some actual use outside of linguistics. Another option is making use of a completely different writing system, but the choice of Latin was because I already use that and of the 1 languages I absolutely speak and 1 language I can speak use this writing system. The only other writing system I know is the Arabic Abjad, and of the 28 official characters, that only extends our valid name capacity by 73HUL entries. It goes further with the extended use characters in other languages or use to accommodate international communication.
One last option is a unique script designed for this explicit purpose. This would require some effort more than what I’ve already put in here. At least for now.



If you see this, your browser does not support JavaScript.

Bonus: JavaScript Popup Dictionary

This shockingly small piece of accessibility is not integrated into every OS or browser in popular use. On current Android devices and Apple products, selecting a section of text will enable you to get a brief definition as brought up by the dictionary engine the device is using or search the web without leaving the tab.
While searching the web is an option, an academic resource really needs a glossary or annex with definitions of words. This little script simply detects when a word of a given CSS class is rolled over. When this happens, it moves an HTML element to the position in question with prepopulated meanings and pronunciations. When the element is rolled off, the element is moved, made transparent, and depopulated for the next word to be loaded up.
The truly hardest part of this was ensuring its functionality on touch devices and ensuring the aesthetics were just right. Positioning is close enough that you can still see it, but just far enough that you aren’t robbed of the sentence context clues.
I would enjoy making this work everywhere on my website, referencing a JSON dictionary, but for the moment, it exists in this article.

Zachary Yarnot and DualVission do not hold any rights to these owners’ contents.
jan Misali is the internet person of Mitchel John Halley.
JavaScript is a trademark of Oracle Corporation.
JSON is a standard maintained by Ecma International created by Douglas Crockford.

Spreadsheets to YAML

One of the most important ways to learn why mistakes are made is by documenting them. Often, recurring treads show why an issue or mistake arises. However, large volumes of data aren’t considered human readable, at least for most people. While in the process of documenting numbers associated with the units on the campus that I work, I found issues with many of our badges and the software that creates them that needed to be documented. Reporting such findings though could be done with software like Microsoft Excel, but the person in charge of overseeing the software does not have a history in data or computer science. As my experience with The Wind Waker Randomizer dv_im reminded me, YAML allows for the construction, maintenance, and readability of data sets, at the small cost of physical space.

YAML is a data language built on many JSON and Python sensibilities. White space denotes relations between objects and their properties. Objects can be built within dictionaries or lists. These two properties are perfect for reporting types of issues as well as keeping things easy to understand.

A basic VBA YAML constructor wouldn’t be too difficult, but a more flexible solution would prove better in the long run. I had originally written this article just after building the more flexible solution, which actually became quite useful. I was only documenting issues that were presenting themselves on visitor badges and patient profiles, but it became clear we also needed to record when software misbehaved or crashed. Having the solution already accommodate new object types was helpful.

Here’s how it was constructed. I knew I wanted two object types: patients and visitors. Each object type would have its own properties we needed to keep track of, as what issues we cared about were different between these two in our visitor management software. Having two different interpreters would be a lot of work for very little benefit. Instead, we know our data table exists in the UsedRange property of our Worksheet object. The top of each column, with the exception of the first, represents the properties of our YAML objects, such as Creator. Each row, with the exception of the first, represents an object. Each cell in a row, with the exception of the first, then is the value or quality of that property, such as zyarnot. The first column represents the dictionary we are building and the keys to the objects within the dictionary.

Knowing how the data is structured in Excel will greatly assist in building a good and efficient system for reading then writing it in the destination format. First, we build a template for the dictionary entries. These will always start with "{1}:" so that we can find where the key must go later. Each cell in this first row represents the title of each property as well as the data type of each property. Unlike VBA, YAML is not explicit with its data types, we are more concerned with data types like lists or non-data types like comments. Each property is added to our template as "{t#}: {v#}" with v being replaced with another character so later the interpreter can recognize what it needs to with the line. Despite the fact comments will be full width without title, I found titles must be declared and inserted before replacing the line, otherwise VBA would error out. Repeat this for each column until the template is complete.

Filling the templates with Replace() is quick work given that every type is implicit except lists and non-data comments, though lists are just an extra step of replacing semicolon-spaces with a newline, an extra tab and a dash with the data then following. Comments must find and replace the title as well as the empty data. Unlike with most YAML interpreters, I elected to have lines with undeclared properties delete the line. If we needed to convert from the YAML back to other methods, I would have the object declaration have optional variables that have default values of empty strings.

This will complete a whole dictionary without much effort. Each dictionary then is just reading a sheet in excel. Again, instead of explicitly declaring “read sheets in this list”, instead it goes through sheets between the how-to and output sheet. Every time the user clicks on the output sheet, data is read and written to it, dividing at about every 37 objects to prevent potential data loss due to cell rendering limits.

Here’s an example of what this simple approach can do:

Input

VisitorsBadgeCreatorIn-opCreatedIssueComments
McTest, John99995zyarnotzyarnot2023.02.05.17.08.25Misspelled first name (no “h”); Misspelled last name (extra “t” at end)How many S’s are in “misspelled”?
Doe, John99994zyarnotzyarnot2023.02.04.21.02.12Wrong category (Should be “Visitor”)

Output

Visitors:
 McTest, John:
  Badge: 99995
  Creator: zyarnot
  In-op: zyarnot
  Created: 2023.02.05.17.08.25
  Issue:
   - Misspelled first name (no "h")
   - Misspelled last name (extra "t" at end)

# How many S's are in "misspelled"?

 Doe, John:
  Badge: 99994
  Creator: zyarnot
  In-op: zyarnot
  Created: 2023.02.04.21.02.12
  Issue:
   - Wrong category (Should be "Visitor")

Zachary Yarnot and DualVission do not hold any rights to these owners’ contents.
Microsoft Excel and Visual Basic for Applications are products of Microsoft Corporation.
Microsoft, Microsoft Office, and Microsoft Excel are registered trademarks of Microsoft Corporation.

Hue Saturation Value

Preface:

Color space representations are important for graphics rendering and a thorough understanding can help creators to effectively use them. Digital artists often are familiar with the standard RGB in sRGB or opRGB color space and its hexadecimal integer representation of the normally qualia-esque thing that is color perception. R, G, and B components then represent the long, mid, and short photosensitive cone ranges respectively. This approximates most colors a human can feasibly see, while keeping data rather small. However, this isn’t the only way to understand color and light.

HSV similarly stores 3 values that each represent light perceived, but instead represent the hue, saturation, and value as the channels. Files often do not store in color data HSV, instead opting to use RGB or color indexing, but HSV is arguably more useful artistically. Since tones and shades are modifications of the variables saturation and value, the exact effect of changing those is immediately obvious. Decreasing saturation will make the color less saturated. This same property does not easily apply in RGB, as decreasing the saturation while maintaining the general color value by small margins is nearly impossible without altering the hue. This is also true in lower color depth situations regardless of color space representation.

Most modern software is well equipped to go between the spaces no problem. That is with the exception of the scripted side of Office (2016 & prior at least). Excel (and other Office applications) will let you adjust the HSV while selecting a color through the UI, but it will store the color as a hexadecimal integer of RGB (stored in BGR order). Adjusting all the colors I want to the specific saturation and value necessary to all items manually is extremely time consuming and mind numbing. This is where VBA comes in handy. We have a problem that can be automated, or more accurately two problems.

Problem 1: Convert RGB values to HSV space

Ironically the easiest part of this how thing.

  1. Split up the single hexadecimal integer [values ranging from 0x000000 to 0xFFFFFF] into 3 floats [values ranging from 0 to 1] (doubles as named in VBA, though singles would likely suffice)
  2. Find the minimum, maximum, and range of those floats
  3. Given order cycle[R, G, B, R, G]
    • Where the first instance of maximum is indexed as i
    • Where the difference of maximum and minimum is d
    • hue = {d≤0: 0, d>0: (60°*(cycle[i+1}-cycle[i+2]))/d+i*120°) mod 360°
    • saturation = d/cycle[i]
    • value = cycle[i]

This all seems simple enough, building functions that effectively represent each step.

Problem 1.1: Interpreting RGB

This problem is basically built into Excel. Start by transferring the decimal long returned using the worksheet function Dec2Hex with the optional minimum return length as 6. The returned string will be 0xBBGGRR, splitting it with the function Mid, and converting it back to decimal with the worksheet function Hex2Dec before dividing it by 255. I recommend adding the optional argument for reversing the order of the input so you can use it for 0xRRGGBB order as well.

Problem 1.2: Hue Calculation

Calculating minimum, maximum, and range is so light weight, there is little reason to separate this as its own step. As well, my as-described functions work well in Python, the lack of lists makes this type of instancing a little less helpful. However, building a switch-case where you compare the maximum to each input instead is effectively the same. I also recommend adding 360° before doing function modulo on these values as function modulo behaves strangely when given negative floats to find the remainder of. While I elected to return a double for hue, I have only seen that function produce integers.

Problem 1.3: Saturation and Value Calculation

It’s honestly harder to get Office to not autocomplete sat as Saturday than calculate these. Value is simply the maximum return on inputs R, G, B while saturation is the ratio of range over maximum of those input.

Problem 2: Going back to RGB

I, as many would assume, thought this step would be easy. For just as many techniques posted only for going from RGB to HSV, there are as many bad techniques for going to RGB from HSV. Whether these functions are bad because of how VBA handles them or just because they were designed before 8-bit color depth is beyond me. This section will read a bit different than the last.

Problem 2.1: The piecewise function approach

  1. Where h' = floor(hue/60°)
  2. Where c = val*sat
  3. Where x = c*(1-|(h' mod 2)-1|
  4. Where m = v-c
  5. 0 ≤ h' < 1 ⇒ (R₁, G₁, B₁) = (c, x, 0)
  6. 1 ≤ h' < 2 ⇒ (R₁, G₁, B₁) = (x, c, 0)
  7. 2 ≤ h' < 3 ⇒ (R₁, G₁, B₁) = (0, c, x)
  8. 3 ≤ h' < 4 ⇒ (R₁, G₁, B₁) = (0, x, c)
  9. 4 ≤ h' < 5 ⇒ (R₁, G₁, B₁) = (x, 0, c)
  10. 5 ≤ h' < 6 ⇒ (R₁, G₁, B₁) = (c, 0, x)
  11. (R, G, B) = (R₁ + m, G₁ + m, B₁ + m)

Why this doesn’t work, I actually have no idea. As you will see with my actual solution, the idea cuts a slice of the color wheel pie into six sections. Each section represents the rise of one channel with the fall of another. The results I was seeing flattened results to the 6 slice edges.

Problem 2.2: The function of n approach

  1. Where k(n) = (n + hue/60°) mod 6
  2. Where f(n) = val - val*sat*max(0, min(k(n),4 - k(n), 1)
  3. (R, G, B) = (f(5), f(3), f(1))

Similarly, I cannot figure out why this wouldn’t simply work. Everything about the function makes some sense, but it resulted in 60° separations rather than actual hues. Maybe it has to do with how VBA does the function modulo.

Problem 3: Dissecting the problem

There was no use of modifying the hue, saturation, and value if there was no way to go back to RGB components. Logically, I needed to visualize the problem. Using Desmos, an online free graphing tool, I rebuilt the hue space graph from the piecewise function. Or more correctly recreate the graph it was emulating. It’s not that hard to recreate it in text, ▔╲▁▁╱▔. It represents over the circular period how much red is present in a given hue. Green is just that offset by 240° and blue by 120°. If I can accurately make that and have it function, we’d have our answer.

Problem 3.1: With Hue

As described before, red can be calculated from a piecewise function characterized by alternating highs and lows through a linear reduction between. This piecewise is periodic with relation to the cycle length, in our case 360° or 2π radians. Naturally, our first step is to find the modulo (remainder) of the input hue: h' = hue mod 360°. For added flexibility, I changed the period to be denoted as c: c = 360°h' = hue mod c. This may seem silly, but altering hue space is the end goal, allowing ourselves the future ability to change the period entirely should be the case. We have found our input for the piecewise function, now to figure out what that piecewise function is.

Segments as you find online described as 6 slices of 60°, but why is that? There is always going to be high state, one in low state, and one in state change. We can then assume that there are 3 segments of high each 120° that are then bisected by which other channel is in state change. The appearance of all three functions overlapping is reminiscent of a suspension bridge and triangle wave forms.

Problem 3.2: High and low states

Next, what is the high state? This is as suggested by the name, the channel that is the strongest or maximum. This just so happens to be our value as calculated before, so t(h') = valval ∈ [0, 1]. That last part does seem a bit confusing but is an unfortunate requirement of these equations. In theory, this all still works with 3 floating point values for R, G, and B where they exist outside of 0 to 1, but no sources I found online suggest this would work.

Low state is naturally, the opposite of high state, being the weakest or minimum channel. This won’t come as freely as high state, but it is embedded in our saturation, being the ratio between difference and maximum. Multiplying saturation by value returns our difference, multiplying by negative one and adding our value will return the minimum, simplified as f(h') = val*(1 - sat)val ∈ [0, 1] & sat ∈ [0, 1].

Our favorite restrictions are back, but here, they begin to make much more sense. With a negative saturation, the minimum would be greater than our maximum, which doesn’t make sense, so restriction could be sat ∈ ℕ. However, if value and or saturation is greater than 1, the output of (R, G, B) ∉ [0,1]³. People dealing with realistic lighting scenarios would have no problem with this; gleam or highlights can exceed 1 and subblacks can be clipped out. This does not fit within our 8-bit color restriction that exists in Office applications. So sandwiching a worksheet function Min with 1 and a worksheet function Max with 0 will keep those numbers in check.

Problem 3.3: Transitional states

As prior stated, these are linear transitions between t(h') and f(h') over c/6, well kind of. Looking at solving this for pure red slowly fading to pure yellow, the duration of change from 0 to 1 for the green channel is 60°, so aG(h') = h'/60°. Red will now decrease from 1 to 0 over 60°, so slope is -h'/60°. Plugging this in won’t have the results we desire, however. It needs to be offset by 2 to account for the shift by 60°, making d(h') = 2 - h'/60°val ∈ [0, 1] & sat ∈ [0, 1]. Those last restrictions can be removed if we consider how transforming this function actually works. The slope is descending 1 unit that is the maximum or val. Multiplying our entire equation, decreasing our requirements to d(h') = val*(2 - h'/60°)sat ∈ [0, 1]. As with any algebraic function, you can add another function to it, so naturally, you would assume d(h') ⊢= val*(2 - h'/60°) + f(h'). This assumption is wrong, as multiplying the slope only by the maximum does not account for when there is low saturation, as slope will continue to be entirely based on full variance. Multiplying the unique part of the function by saturation leaves it entirely based on the difference, making d(h') = val*sat*(2 - h'/60°) + f(h') or d(h') = val*sat*(2 - h'/60°) + val(1 - sat).

Future proofing with assuming that a cycle isn’t 360° is genuinely easy. h'/60° is a representation of 6h'/360°. Replacing 360° with c returns d(h') = val*sat*(2 - 6h'/c) + f(h') or d(h') = val*sat*(2 - 6h'/c) + val(1 - sat).

The ascending transitional state is also fairly trivial given our knowledge of when the states occur and the duration of ascension. When at zero, aG(h') didn’t need any offsets. When at the first sixth, d(h') needed an offset of 2, and descent will need to always be increased by an additional one to align with [0,1] space. We should expect at 240° that d(h') = val*sat*(6h'/c - 4) + f(h') or d(h') = val*sat*(6h'/c - 4) + val(1 - sat).

Problem 3.4: Piecewise referencing

Writing a piecewise function in VBA would be silly given the scripting language already has logic systems in place. For those math lovers, here’s what the function looks like given Desmos/Office notation: r(h') = {0 ≤ h' < c/6: t(h'), c/6h' < c/3: d(h'), c/3h' < 2c/3: f(h'), 2c/3h' < 5c/6: a(h'), 5c/6h' < c: t(h')}. As stated before g(h') = r((h' + 2c/3) mod c) and b(h') = r((h' + c/3) mod c). After setting this up in Desmos, you can really see how hue, saturation, and value shifting actually work. When you compare this to the piecewise solution described before, it becomes more confusing why it didn’t work. Maybe it has to do with when variables are assigned, causing it to become a rounding error. Breaking it down this way does make it far easier to understand why things need to be a certain way.

Bonus: Pseudosinusoidal ≠ Sinusoidal

Throughout this piece, you may recognize the continuous use of referring to the transitional state as linear, but why can’t truncated cosine wave function? They have the same period, peaking every rotation of a circle. To our eyes, rc(h') = val*sat*max(0, min(1, ½(2cos(h') + 1)) + val(1 - sat), but it only approximates the correct value. The peaks and valleys are 100% accurate, but transitioning is not as pretty. The ratio between this approximation and reality depends on saturation, becoming more extreme as it increases. Its gentler transition may be worth the margin of error for some.

Zachary Yarnot and DualVission do not hold any rights to these owners’ contents.
Desmos is a product of Amplify and Desmos Studio.
Desmos Studio and Desmos are trademarks of Amplify.
Microsoft Excel and Visual Basic for Applications are products of Microsoft Corporation.
Microsoft, Microsoft Office, and Microsoft Excel are registered trademarks of Microsoft Corporation.