Daddy needs a new pair of RAM!

edit: the fps are way better in smaller terminal windows with lower character count but then it’s hard to make out the dice. D:

edit2: code here (expires in 2 weeks)

        • RheumatoidArthritis@mander.xyz
          link
          fedilink
          arrow-up
          17
          ·
          1 day ago

          I didn’t have the patience to do it myself bit wanted to see just how complex it would get:

          fp32_mul() {
              local a=$1 b=$2
              local sa=$(( (a >> 31) & 1 ))
              local sb=$(( (b >> 31) & 1 ))
              local sign=$((sa ^ sb))
          
              local ea=$(( (a >> 23) & 0xff ))
              local eb=$(( (b >> 23) & 0xff ))
              local fa=$(( a & 0x7fffff ))
              local fb=$(( b & 0x7fffff ))
          
              # NaN / infinity / zero handling
              if (( ea == 255 )); then
                  if (( fa != 0 )); then
                      printf '%08x\n' $((0x7fc00000))
                      return
                  fi
                  if (( eb == 0 && fb == 0 )); then
                      printf '%08x\n' $((0x7fc00000))   # inf * 0 = NaN
                      return
                  fi
                  printf '%08x\n' $(((sign << 31) | 0x7f800000))
                  return
              fi
          
              if (( eb == 255 )); then
                  if (( fb != 0 )); then
                      printf '%08x\n' $((0x7fc00000))
                      return
                  fi
                  if (( ea == 0 && fa == 0 )); then
                      printf '%08x\n' $((0x7fc00000))
                      return
                  fi
                  printf '%08x\n' $(((sign << 31) | 0x7f800000))
                  return
              fi
          
              if (( ea == 0 && fa == 0 || eb == 0 && fb == 0 )); then
                  printf '%08x\n' $((sign << 31))
                  return
              fi
          
              # Convert subnormals to a normalized significand/exponent.
              # m is a 24-bit significand for normals.
              local ma mb
              if (( ea == 0 )); then
                  ma=$fa
                  ea=1
                  while (( (ma & 0x800000) == 0 )); do
                      ma=$((ma << 1))
                      ((ea--))
                  done
              else
                  ma=$((fa | 0x800000))
              fi
          
              if (( eb == 0 )); then
                  mb=$fb
                  eb=1
                  while (( (mb & 0x800000) == 0 )); do
                      mb=$((mb << 1))
                      ((eb--))
                  done
              else
                  mb=$((fb | 0x800000))
              fi
          
              # Multiply the two 24-bit significands.
              # Product is up to 48 bits.
              local p=$((ma * mb))
              local e=$((ea + eb - 127))
          
              # Normalize product.
              #
              # ma*mb has binary point after bit 46.  If bit 47 is set,
              # product is [2,4), otherwise [1,2).
              local shift
              if (( p & 0x800000000000 )); then
                  shift=24
                  ((e++))
              else
                  shift=23
              fi
          
              # Extract 23 fraction bits plus guard/round/sticky information.
              local frac=$(( (p >> shift) & 0x7fffff ))
              local guard=$(( (p >> (shift - 1)) & 1 ))
              local round=$(( (p >> (shift - 2)) & 1 ))
              local sticky=0
          
              if (( shift >= 3 )); then
                  local mask=$(( (1 << (shift - 2)) - 1 ))
                  (( (p & mask) != 0 )) && sticky=1
              fi
          
              # Round-to-nearest, ties-to-even.
              if (( guard && (round || sticky || (frac & 1)) )); then
                  ((frac++))
                  if (( frac == 0x800000 )); then
                      frac=0
                      ((e++))
                  fi
              fi
          
              # Overflow -> infinity.
              if (( e >= 255 )); then
                  printf '%08x\n' $(((sign << 31) | 0x7f800000))
                  return
              fi
          
              # Normal result.
              if (( e > 0 )); then
                  printf '%08x\n' $(((sign << 31) | (e << 23) | frac))
                  return
              fi
          
              # Underflow into the subnormal range.
              #
              # At this point the normalized significand represented by
              # (1.frac) must be shifted right by 1-e positions.
              local mant=$((0x800000 | frac))
              local rshift=$((1 - e))
              local lost=0
              local halfway=0
              local low=0
          
              if (( rshift >= 25 )); then
                  # Everything rounds to zero (unless the exact value is
                  # sufficiently close, which it cannot be here).
                  mant=0
              else
                  low=$((mant & ((1 << rshift) - 1)))
                  mant=$((mant >> rshift))
          
                  halfway=$((1 << (rshift - 1)))
          
                  if (( low > halfway || (low == halfway && (mant & 1)) )); then
                      ((mant++))
                  fi
              fi
          
              # Rounding a subnormal can produce the smallest normal.
              if (( mant >= 0x800000 )); then
                  printf '%08x\n' $(((sign << 31) | (1 << 23)))
              else
                  printf '%08x\n' $(((sign << 31) | mant))
              fi
          }
          
    • Pudutr0n@lemmy.worldOP
      link
      fedilink
      arrow-up
      14
      ·
      1 day ago

      Jebus I don’t even know how long I’ve been working on this. It started out as a way to teach myself bash, combined with my long obsession with rendering platonic solids. I previously coded a huge galaxy of hundreds of thousands of polyhedra you could fly across in python with opengl shaders and got to reuse/translate a lot of that code. The quaternion stuff I was grateful to not have to rethink that much again. haha. And yes, integer-only! Some params are “floating point” but i just parse them and add a bunch of zeroes so i can later do all the operations with equally blown up values of pi and trig stuff from “lookup tables” (case matching).