my newest bits read / write

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
dafhi
Posts: 1673
Joined: Jun 04, 2005 9:51

my newest bits read / write

Post by dafhi »

in case anyone is bored, it's fun to post code. i read through comments on one of my older posts in Tips & Tricks, someone mentioned "post in General instead if it hasn't been well tested"

i'm notorious for releasing untested code. it's my thing. i just like to inspire

anyway, here is my newest bit hacking framework.

it's been tested some [major correction in Feb 23 update 2]

Code: Select all

/' -- bit-aligned read / write (up to 57 bits) - 2024 Feb 29

    Why 57 ?
  
  internal var b_offs can maximally represent an offset of 7:
  00000001
  
  that bit plus up to 7 more bytes = 57 bits
 
   - dafhi
  --------
  
   updates documented at their locality

'/


''
'' -- bits printout .. MSB left
''
function sbin(p as any ptr, cBits as longint = 1) as string
  
  static as string  ret:  ret = "" '' 2024 Feb 25
  dim as long       cbytes = (cbits + 7) \ 8
  dim as ubyte ptr  b = p + cbytes - 1  
  
  for j as long = 1 to cBytes
    var s = ""
    for i as long = 7 to 0 step -1
      s += str((*b shr i) and 1)
    next
    ret += s + " "
    b -= 1
  next
  return ret
  
end function


#define min( a, b)        iif( (a)<(b), (a), (b) )
#define max( a, b)        iif( (a)>(b), (a), (b) )

'' reduced text
#define dbl         as double

function clamp( in dbl, hi dbl = 1, lo dbl = 0) dbl
  return min( max(in, lo), hi ) '' 2023 June 12
End Function


' -- support
'
union uptrs           '' i forget who suggested (avoids sus ptr)
  as any ptr          a
  as ubyte ptr        b
  as ushort ptr       sho
  as ulong ptr        l
  as ulongint ptr     li
  As Single Ptr       s
  as double ptr       d
End Union


  namespace ba57 ' bit aligned read / write - 2024 Feb 29 - by dafhi
  
  /' -- usage
  
  dim as byte  a(5)
  ba57.pdata = @a(0)
  ba57.wri valu, offs, cbits_0_to_57
    var result = _
  ba57.rea( offs, cbits_0_to_57 )
'/

  '' support
  dim as any ptr    pdata

  dim as ulongint   b_offs, mask
  
  dim as uptrs      gp

  sub _rw_common( bpos as ulongint, byref c as byte )
    gp.a   = pdata + bpos \ 8 '' integer divide
    b_offs = bpos - (bpos \ 8) * 8
    c      = clamp( c, 57 )
    mask = ( (1 shl c)-1 ) shl b_offs
    'mask = ((culngint(1) shl c)-1) shl b_offs  ' Feb 29
  end sub

'' main functions
''
function rea( bitpos as ulongint, cbits as byte = 1 ) as ulongint
  _rw_common bitpos, cbits
  return (*gp.li and mask)shr b_offs
end function

sub wri( valu as ulongint, bitpos as ulongint, cbits as byte = 1 )
  _rw_common bitpos, cbits
  *gp.li xor= *gp.li and mask
  *gp.li or= (valu shl b_offs)and mask
end sub

end namespace



''
'' Main
''
dim as ulongint a
ba57.pdata = @a

print " bit-aligned read / write"
print

print " wri"

var valu = -1
var offs = 7
var size = 2
ba57.wri valu, offs, size

'var data_size_in_bits = 5 * 8  ' Feb 29
var print_size_in_bits = 5 * 8
print sbin( @a, print_size_in_bits )

print " rea"

var result = ba57.rea( offs, print_size_in_bits - offs )

print sbin( @result, print_size_in_bits );
print " (from bit"; offs; ")"
SamL
Posts: 58
Joined: Nov 23, 2019 17:30
Location: Minnesota

Re: my newest bits read / write

Post by SamL »

cool!
i'm inspired :D
here is some code that i made for a personal use datatype.
the uDecimal datatype, unsigned decimal that can hold values from 0.0 to 18446744073709551615.999999999999999999
I have some operators and cast functions made for it but it's incomplete ( not full feature datatype ) but works for what i need.
i'm sure this is an elementary way of making datatypes but it's my first one.

Code: Select all

type uDecimal 'unsigned decimal
    as ulongint w = 0'whole value
    as ulongint d = 1000000000000000000 'decimal value (max decimal points 18 )
end type

declare function udeci_str( n as uDecimal ) as string
declare function cudeci overload( n as string ) as uDecimal
declare function cudeci overload ( n as double ) as uDecimal
declare function cudeci overload ( n as ulongint ) as uDecimal 'supports all unsigned integer types
'declare function udeci_udbl( n as udecimal ) as double
declare function udeci_ulngint( n as  udecimal ) as ulongint
declare function udeci_str_w(n as uDecimal) as string
declare function udeci_str_d(n as uDecimal) as string

declare operator + ( byref n1 as uDecimal, byref n2 as uDecimal ) as uDecimal
declare operator - ( byref n1 as uDecimal, byref n2 as uDecimal ) as uDecimal
declare operator = ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
declare operator <> ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
declare operator < ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
declare operator > ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
declare operator <= ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
declare operator >= ( byref n1 as uDecimal, byref n2 as uDecimal ) as long

declare function zero_uDecimal() as uDecimal 

function udeci_ulngint( n as  udecimal ) as ulongint
    function = n.w
end function

'function udeci_udbl( n as udecimal ) as double
'    'does not work when n = 0, function = ((n.d - 1000000000000000000) / 1000000000000000000) + n.w
'end function

function udeci_str( n as uDecimal ) as string
    dim as string*19 d
    d = str(n.d)
    for i as long = 1 to 18
        d[i-1] = d[i]
    next i
    d[18] = 0 'string nul for end of string
    return str(n.w) & "." & d
end function

function udeci_str_d(n as uDecimal) as string
    dim as string*19 d
    d = str(n.d)
    for i as long = 1 to 18
        d[i-1] = d[i]
    next i
    d[18] = 0 'string nul for end of string
    return "." & d
end function

function udeci_str_w(n as uDecimal) as string
    return str(n.w)
end function

function cudeci( byref n as string ) as uDecimal
    dim as string*50 w
    dim as string*19 d '18 is the max
    dim as byte len_n = len(n)-1
    dim as byte i 
    dim as byte decimal_loc
    dim as byte index_offset
    dim r as uDecimal
    for i = 0 to len_n-1'scan input for a decimal point.
        if n[i] = 46 then ' 46 = "." the decimal point was found.
            decimal_loc = i
            goto parse_decimal
        end if
    next i
    goto parse_whole 'skip parsing the decimal, because it does not exist
    parse_decimal:
    index_offset = 1
    for i = decimal_loc+1 to len_n
        d[index_offset] = n[i]
        index_offset += 1 'start at 2 for data, [0] is reserved for leading 1
        if index_offset = 19 then exit for 'trims any over flow with out rounding
    next i
    parse_whole:
    'assume there is no garbage or over flow in string
    for i = 0 to decimal_loc-1
        w[i] = n[i]
    next i
    'finish up decimal value
    if index_offset < 19 then
        for i = index_offset to 18 'fill the string with zeros
            d[i] = 48 '48 = "0"
        next i
    end if
    d[0] = 49'49 = "1" 'left most padding to preserve decimal value.
    r.w = culngint(w)
    r.d = culngint(d)
    return r
end function

function cudeci ( n as double ) as uDecimal
    function = cudeci(str(n)) 'just doing this for now. 
end function

function cudeci ( n as ulongint ) as uDecimal
    dim r as uDecimal
    r.w = n
    return r
end function

operator + ( byref n1 as uDecimal, byref n2 as uDecimal ) as uDecimal
    dim as uDecimal r
    r.d = n1.d + n2.d
    if r.d > 2999999999999999999 then 'carry 
        r.w = n1.w + n2.w + 1
        r.d -= 2000000000000000000 'ajust padding value
    else
        r.w = n1.w + n2.w
        r.d -= 1000000000000000000 'ajust padding value
    end if
    return r
end operator

operator - ( byref n1 as uDecimal, byref n2 as uDecimal ) as uDecimal
    dim as uDecimal r
    r.d = 1000000000000000000 + n1.d - n2.d 
    if r.d < 1000000000000000000 then 'need to borrow
        r.w = n1.w - n2.w - 1 'borrow from whole number
        r.d += 1000000000000000000 'add the borrow value to decimal
    else 'no borrow
        r.w = n1.w - n2.w
    end if
    return r
end operator

operator = ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w = n2.w and n1.d = n2.d then return -1 'return true
    return 0 'false
end operator

operator <> ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w = n2.w and n1.d = n2.d then return 0 
    return -1 'false
end operator

operator < ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w < n2.w then return -1 'return true
    if n1.w > n2.w then return 0 'return false
    if n1.d < n2.d then return -1 'return true
    return 0 'false
end operator

operator > ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w > n2.w then return -1 'return true
    if n1.w < n2.w then return 0 'return false
    if n1.d > n2.d then return -1 'return true
    return 0 'false
end operator

operator <= ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w < n2.w then return -1 'return true
    if n1.w > n2.w then return 0 'return false
    if n1.d < n2.d then return -1 'return true    
    if n1.w = n2.w and n1.d = n2.d then return -1 'return true
    return 0 'false
end operator

operator >= ( byref n1 as uDecimal, byref n2 as uDecimal ) as long
    if n1.w > n2.w then return -1 'return true
    if n1.w < n2.w then return 0 'return false
    if n1.d > n2.d then return -1 'return true
    if n1.w = n2.w and n1.d = n2.d then return -1 'return true
    return 0 'false   
end operator

function zero_uDecimal() as uDecimal
    function = type<uDecimal>
end function
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

Re: my newest bits read / write

Post by hhr »

A suggestion for an example:

Code: Select all

dim as udecimal a,b,c,d
a = cudeci("123456789.123230000023000001")
b = cudeci("545676666.997555555559999999")
c = a + b
d = b - a
print udeci_str(c),udeci_str(d)
c = c + d
print udeci_str(c)
d = b + b
print udeci_str(d)
print c = d, c > d, c >= d, c < d, c <= d, c <> d
sleep
Post Reply