Skip to content

Instantly share code, notes, and snippets.

@Quackward
Created August 29, 2021 10:22
Show Gist options
  • Save Quackward/b01b9373ad446040d5c6de6bc6c70f05 to your computer and use it in GitHub Desktop.
Save Quackward/b01b9373ad446040d5c6de6bc6c70f05 to your computer and use it in GitHub Desktop.

Revisions

  1. Quackward created this gist Aug 29, 2021.
    88 changes: 88 additions & 0 deletions RatioProposal.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    // `Ratio` :: fixed point type representing values [0.0 to 1.0]
    // + automatic bounds clamping
    // + linear distribution of values, aligned to map cleanly with 1/2^n fractions
    // - sacrifices ~1 bit of entropy;has no division operator
    //
    // Exponent
    // | ___Mantissa___ if exponent is 1, the value is [1.0] ignoring mantissa
    // | | | mantissa is always cleared if an operation produces 1.0
    // 0 0 0 0 0... 0 0 0
    // | | | etc... if exponent is 0, the value is [0.0 to 1.0 - epsilon]
    // | | +1/8 depending on the mantissa, where each bit adds:
    // | +1/4 ` 1/2^bitIndex `, where bitIndex starts at 1
    // +1/2
    //
    // add (simple integer addition)
    // (if exponent is 1 on either operand or the result, clear mantissa)
    // sub (simple integer subtraction)
    // (if exponent is 1 on rhs operand or the result, clear everything)
    // mul (simple [to a computer] fixed point multiplication)
    // (this operation will never set the exponent if neither operand has it set)
    // (if exponent is 1 in either operand, this returns the opposite operand)
    // div doesn't exist for this type, a promotion to float is required
    // div HOWEVER can produce an accurate float reciprical quickly, and multiply the
    // dividend by that instead, as a potential shortcut when used as a divisor
    // float promotion is trivial:
    // exponent ? 1.0f : (1.0f | mantissa<<(23-bitsize)) - 1.0f;
    //
    //--------------------------------------------------------------------------------------------------
    //
    // `Turn` :: a type representing a circular range through 0.0 to +/-1.0 and back
    // range is less like a number LINE and more like a number CIRCLE (think angles):
    // +/-0.0 and +/-1.0 are opposed, and +0.5 and -0.5 are similarly opposed;
    //
    // +0.5
    // o O o
    // +0.25 O O +0.75
    // o o
    // o o
    // +/-0.0 O o ------- O +/-1.0
    // o o
    // o o
    // -0.25 o o -0.75
    // O o O
    // -0.5
    //
    // USES
    // > as normals with acceptable fidelity using 2x 8bit or 16bit Turns (theta and phi)
    // > as trig function inputs with built-in bounds and usable directly as LUT index
    //
    // PROS
    // + well defined overflow and underflow
    // + linear distribution of values, aligned to map cleanly with 1/2^n fractions
    // + sacrifices 0 entropy, no special cases, all values are valid
    // + 32-bit, 16-bit, and 8-bit precisions
    // + float promotion is free
    // + accurate float reciprical free; allows for fast division if Ratio is the divisor
    // CONS
    // - +/- 1.0 is an odd concept to grasp, has no satisfying mapping in float
    // - division with float operand must convert to float and use float division
    //
    // Sign
    // | ___Mantissa___ if sign is 0, the value is [`+/-0.0` to `1.0 - epsilon`]
    // | | | if sign is 1, the value is [`+/-1.0` to `0.0 - epsilon`]
    // 0 0 0 0 0... 0 0 0
    // | | | etc... value is the mantissa, where each bit adds:
    // | | +1/8 ` 1/(2^bitIndex) `, where bitIndex starts at 1
    // | +1/4 if sign is set, -1.0 is deducted from the value
    // +1/2 1.0 has no sign, positive or negative.
    //
    // operators:
    // add (simple integer addition with 2's compliment overflow)
    //
    // sub (simple integer subtraction with 2's compliment underflow)
    //
    // mul (simple [to a computer] fixed point multiplication)
    // (if either operand is +/- 1.0, return the other operand)
    // (if either operand is +/- 0.0, return 0.0)
    // (else this operation sets the result's sign to XOR of both operand signs)
    //
    // div doesn't exist for this type, without promotion to float
    // HOWEVER, can produce an accurate float reciprical quickly, and multiply the
    // dividend by that instead, as a fast shortcut when used as a divisor
    //
    // float promotion is trivial, though +/- 1 is an unusual case with no analog,
    // (maybe best to assign that the identity value +1)
    // ~value ? 1.0f :
    // sign ? (((1.0f | mantissa<<(23-bitsize)) - 1.0f) | (1<<(bitwidth-1)))
    // : ((1.0f | mantissa<<(23-bitsize)) - 1.0f);