▲ 508 ▼ I wrote a dice rolling script with 3d rendering, collisions and friction in bash because why not [edit: code available now] (files.catbox.moe) submitted 5 days ago* (last edited 4 days ago) by Pudutr0n@lemmy.world to c/programming@programming.dev 99 comments fedilink hide all child comments 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)
[–] SpaceNoodle@lemmy.world 21 points 5 days ago (1 child) All computer math is integer math if you go deep enough permalink fedilink source parent hideshow 2 child comments replies: [–] RheumatoidArthritis@mander.xyz 9 points 5 days ago (3 children) I'm sure implementing floating point directly in bash would work great permalink fedilink source parent hideshow 6 child comments replies: [–] RheumatoidArthritis@mander.xyz 17 points 5 days ago (1 child) 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 } permalink fedilink source parent hideshow 2 child comments replies: [–] RheumatoidArthritis@mander.xyz 15 points 5 days ago (1 child) 1440 multiplications per second on my computer! permalink fedilink source parent hideshow 2 child comments replies: [–] Womble@piefed.world 19 points 5 days ago Wow, over a kiloflop! permalink fedilink source parent [–] Pudutr0n@lemmy.world [S] 7 points 5 days ago hahaha you seem to be familiar with the issues I ran across permalink fedilink source parent [–] tabular@lemmy.world 4 points 5 days ago Invert the gravity value and then all the dice will be floating point 🫣 permalink fedilink source parent
[–] RheumatoidArthritis@mander.xyz 9 points 5 days ago (3 children) I'm sure implementing floating point directly in bash would work great permalink fedilink source parent hideshow 6 child comments replies: [–] RheumatoidArthritis@mander.xyz 17 points 5 days ago (1 child) 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 } permalink fedilink source parent hideshow 2 child comments replies: [–] RheumatoidArthritis@mander.xyz 15 points 5 days ago (1 child) 1440 multiplications per second on my computer! permalink fedilink source parent hideshow 2 child comments replies: [–] Womble@piefed.world 19 points 5 days ago Wow, over a kiloflop! permalink fedilink source parent [–] Pudutr0n@lemmy.world [S] 7 points 5 days ago hahaha you seem to be familiar with the issues I ran across permalink fedilink source parent [–] tabular@lemmy.world 4 points 5 days ago Invert the gravity value and then all the dice will be floating point 🫣 permalink fedilink source parent
[–] RheumatoidArthritis@mander.xyz 17 points 5 days ago (1 child) 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 } permalink fedilink source parent hideshow 2 child comments replies: [–] RheumatoidArthritis@mander.xyz 15 points 5 days ago (1 child) 1440 multiplications per second on my computer! permalink fedilink source parent hideshow 2 child comments replies: [–] Womble@piefed.world 19 points 5 days ago Wow, over a kiloflop! permalink fedilink source parent
[–] RheumatoidArthritis@mander.xyz 15 points 5 days ago (1 child) 1440 multiplications per second on my computer! permalink fedilink source parent hideshow 2 child comments replies: [–] Womble@piefed.world 19 points 5 days ago Wow, over a kiloflop! permalink fedilink source parent
[–] Pudutr0n@lemmy.world [S] 7 points 5 days ago hahaha you seem to be familiar with the issues I ran across permalink fedilink source parent
[–] tabular@lemmy.world 4 points 5 days ago Invert the gravity value and then all the dice will be floating point 🫣 permalink fedilink source parent