Hi, I'm a newby to this, working on learning Haskell for scientific
computation & see this code looks like Haskell. Is this a package?
thanks, Jeffrey
> *m = truncateB ((m1' * m2') .>>. 23) :: Word23*
>
> to
>
> *m = truncateB ((m1' * m2' + bit 22) .>>. 23) :: Word23*
>
> and that would make me, if nobody else, happier.
>
> With respect to errors, the general principle is to not error. Instead one
> should produce a "NaN", which is (_,-1,*) as an IEEE triple
> (Bool,Int8,Word23) (i.e., sign,exponent,mantissa). The -1 is the exponent
> part. The * for the matissa part should be non-zero. That's because
> (_,-1,0) is infinity. NaNs should ideally be preserved through
> calculations, so most of the calculations I gave should have an extra first
> line or two to pick out the situation when one of the arguments to the
> floating point operation is a NaN, and make the result a NaN. I would
> suggest for multiplication, for example, a guard line like
>
> *myMulFloat (s1,-1,m1) (s2,e2,m2) = (s1/=s2,-1,m1)* -- NaN * _ =
> NaN
>
> Sticklers may wish to pick out the infinity case just before that, so
> infinity times zero can be detected, and NaN produced. Otherwise one will
> get some ordinary value, and I have no clue what it will be. Maybe zero.
> Surely zero. I've kept the sign calculation as-is above, because it's info.
>
> To build a complete floating point operation one does (for example)
>
>
>
> *mul_f :: Float -> Float -> Floatmul_f x y = myencodeFloat(muMulFloat
> (mydecodeFloat x) (mydecodeFloat y))*
>
> The simplest encoding/decoding function expressions are probably:
>
>
> *myencodeFloat :: (Bool,Int8,Word23) -> FloatmyencodeFloat
> (zSign,zExp,zFrac) = unpack (pack zSign ++# pack zExp ++# pack zFrac)*
>
> *mydecodeFloat :: Float -> (Bool,Int8,Word23) *-- sign, exponent, mantissa
> (significand without leading bit)
>
>
>
>
> *mydecodeFloat x = (zSign,zExp,zFrac) where x' = pack x ::
> BitVector 32 zSign = testBit x' 31
> :: Bool zExp = unpack( truncateB(x' .>>. 23)) ::
> Int8 zFrac = unpack( truncateB x') :: Word23*
>
> You should be able to do much better with more access to and knowledge of
> Clash internals. This assumes the haskell internal representation is the
> standard IEEE binary interchange format, and I believe it is. But on an
> other-endian machine that story needs checking.
>
> I would really appreciate it if somebody would produce a new backend
> primitive operation from this. I have not succeeded in making head nor tail
> of the tutorial exposition, I am afraid - it fails to tell me what you
> want, so I don't know what to supply, let alone how. I can dump a system
> verilog "module" for the mul_f above, for example. Here it is! Please
> modify as required, and maybe I can spot what is needed from that.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> */* AUTOMATICALLY GENERATED SYSTEMVERILOG-2005 SOURCE CODE.** GENERATED BY
> CLASH 1.2.4. DO NOT MODIFY.*/`timescale 100fs/100fsmodule FPUa_mul_f (
> result = (c$case_alt);endmodule*
>> *myDivFloat :: (Bool,Int8,Word23) -> (Bool,Int8,Word23) ->
>> (Bool,Int8,Word23)*
>> *myDivFloat (s1,0,0) (s2,e2,m2) = (s1/=s2,0,0) -- **(new
>> trap for 0/..)*
>>
>>
>>
>> *myDivFloat (s1,e1,m1) (s2,e2,m2) = (s,e,m) where s = s1 /=
>> s2 :: Bool*
>> * e = (e1 - 127) - (e2 - 127) + 128 :: Int8 -- **(was
>> +127)*
>>
>> * m1' = setBit (zeroExtend m1) 23 :: Word48 -- **caculate
>> in 48b*
>>
>>
>> * m2' = setBit (zeroExtend m2) 23 :: Word48*
>> * m = truncateB ((m1' .<<. 24) `div` m2'):: Word23 -- **(was
>> .<<. 23)*
>>
>> I should trap for 0 as divisor too, but I don't recall the NaN format
>> (one
>> of them!) so I won't. Please somebody look it up and trap for ../0.
>>
>> Hmm. I also forgot the trap for 0 as multiplicand in the multiplication
>> operator. Please rescue as follows:
>>
>>
>>
>>
>> *myMulFloat :: (Bool,Int8,Word23) -> (Bool,Int8,Word23) ->
>> (Bool,Int8,Word23)myMulFloat (s1,0,0) (s2,e2,m2) = (s1/=s2,0,0)myMulFloat
>> (s1,e1,m1) (s2,0,0) = (s1/=s2,0,0)myMulFloat (s1,e1,m1) (s2,e2,m2) = ...*
>>
>> The s1/=s2 business is so one can have the thrill of seeing an occasional
>> "-0.0" pop out as result. Who am I to say no.
>>
>> So, apologies, mea culpa, and errati apart, take a deep breath and on to
>> addition/subtraction. I'll get rid of having to consider the sign bit by
>> reducing everthing to sum of two positive numbers, or difference of two
>> positive numbers, before even thinking:
>>
>>
>>
>>
>> *myAddFloat :: (Bool,Int8,Word23) -> (Bool,Int8,Word23) ->
>> (Bool,Int8,Word23)myAddFloat (s1,e1,m1) (s2,e2,m2) = case (s1,s2) of
>> (False,False) -> myAddFloatPos (e1,m1) (e2,m2) -- **pos +
>> pos*
>> * (False,True) -> mySubFloatPos (e1,m1) (e2,m2) --
>> **pos
>> + neg*
>> * (True,False) -> let (s,e,m) = mySubFloatPos (e1,m1) (e2,m2) --
>> **neg
>> + pos*
>>
>> * in (not s,e,m) (True,True) -> let (s,e,m) =
>> myAddFloatPos (e1,m1) (e2,m2) -- **neg + neg*
>>
>>
>>
>>
>> * in (not s,e,m)mySubFloat :: (Bool,Int8,Word23) ->
>> (Bool,Int8,Word23) -> (Bool,Int8,Word23)mySubFloat (s1,e1,m1) (s2,e2,m2)
>> =
>> myAddFloat (s1,e1,m1) (not s2,e2,m2)*
>>
>> I set subtraction to be just addition of a negative, since all I have to
>> do to negate a number is change its sign bit in the IEEE triple ... and
>> hope. (You can just see that I ought to trap for zero here too, but let's
>> go on without ...).
>>
>> All I have to do to add up two positive numbers is put back the leading 1
>> on the mantissas and add as integers, then take the leading 1 back off to
>> get the mantissa of the result.
>>
>> I'll have to watch for the leading 1 moving left one place (when one does
>> large + large), in order to hit it when aiming to knock it off, which is
>> the "testBit m 24" below. The addends have leading 1 in position 23, so
>> adding the leading 1 either stays in position 23 or moves one left to
>> position 24. In the latter case I have to drop the 0th bit of the result,
>> losing 1 bit of precision,
>> but keeping to the allotted 23 bits for the mantissa. That means a shift
>> right by 1 (" .>>. 1"). The leading 1 gets dropped in any case by the
>> obligatory truncation to 23 bits for the mantissa.
>>
>>
>>
>>
>> *myAddFloatPos :: (Int8,Word23) -> (Int8,Word23) ->
>> (Bool,Int8,Word23)myAddFloatPos (e1,m1) (e2,m2) = if
>> testBit m 24 then (False,e+1,truncateB (m .>>. 1) ::
>> Word23) -- **grew!*
>>
>>
>> * else (False,e, truncateB m :: Word23)
>> where m1' = setBit (zeroExtend m1) 23 :: Word25 -- **caculate in
>> 25b*
>>
>>
>>
>>
>> * m2' = setBit (zeroExtend m2) 23 :: Word25 (e,m) = case
>> undefined of _ | e1-e2 > 0 -> (e1, m1' + (m2' .>>.
>> fromEnum(e1-e2))) _ | e1-e2 < 0 -> (e2, (m1' .>>.
>> fromEnum(e2-e1)) + m2') _ | e1 == e2 -> (e1, m1' + m2')*
>>
>> I had to shift the smaller addend to the right to match up its digits in
>> the correct places with the digits of the larger addend. That loses some
>> precision. The more caring should round rather than truncate when doing
>> the
>> shift right.
>>
>> I yet have to handle subtraction of two positive numbers (below). This
>> splits into several cases according to whether to expect a positive
>> (nonegative) or negative result. Those cases are large - small and small
>> -
>> large, plus a couple in which it is harder to tell. One can primarily
>> tell
>> by which has the larger exponent. If the exponents are equal, one can
>> tell
>> by which has the larger mantissa. If the mantissas are equal too, then
>> the
>> answer for the subtraction is 0. I will use "ff1" to return the position
>> of
>> a leading 1:
>>
>>
>>
>>
>> *mySubFloatPos :: (Int8,Word23) -> (Int8,Word23) ->
>> (Bool,Int8,Word23)mySubFloatPos (e1,m1) (e2,m2) = (s,e',m')
>> where m1' = setBit (zeroExtend m1) 23 ::
>> Word25 -- **calculate in 25b*
>>
>> * m2' = setBit (zeroExtend m2) 23 :: Word25 --
>> **shift
>> left or right if leading 1 not in expected posn 23*
>>
>>
>>
>>
>> * (e',m') = let n = if e1==e2 && m1==m2 then 23 else ff1
>> m in case n of
>> 23 -> (e, truncateB m ::
>> Word23) _ | n >
>> 23 -- **impossible*
>>
>> * -> (e-toEnum(23-n),truncateB (m .>>. (n-23)) ::
>> Word23) _ | n < 23
>> -- **implausible*
>>
>>
>> * -> (e-toEnum(23-n),truncateB (m .<<. (23-n)) ::
>> Word23) (s,e,m) = case undefined of _ |
>> e1-e2
>> > 0 -> (False,e1,m1'-(m2' .>>. fromEnum(e1-e2))) -- **big minus small*
>> * _ | e1-e2 < 0 -> (True,e2, m2'-(m1' .>>.
>> fromEnum(e2-e1))) -- **small minus big*
>> * _ | m2 < m1 ->
>> (False,e1,m1'-m2') -- **big minus small*
>> * _ | m1 < m2 -> (True,e2,
>> m2'-m1') -- **small minus big*
>> * _ ->
>> (False,0,0) **--* *x - x = 0*
>>
>> In the x-x case, I have sneaked a (_,0,0) result by setting an imaginary
>> "leading 1 position" on the intermediate result at 23, the expected
>> default
>> position, which will stop the code attempting to further mutate it. (That
>> I
>> have to explain it means it is wrong code, in software engineering terms
>> --
>> just trap for a zero result at top level and skip the subterfuge).
>>
>> All that needs much more testing than I have given it. The subtraction is
>> the more delicate code. It invokes the addition. So here is a test:
>>
>>
>>
>>
>> *> myencodeFloat(mySubFloat (mydecodeFloat 17.3) (mydecodeFloat 9.3))
>> 8.0>
>> myencodeFloat(mySubFloat (mydecodeFloat 17.3) (mydecodeFloat 19.3))-2.0*
>>
>> Yes, I have tried subtracting and adding negative numbers. Please try
>> more
>> and let me know what I got wrong.
>>
>> I forgot to give a function that maps from float to integer. This one
>> truncates towards zero (which I hate ... but may even be right in some
>> universe, maybe the IEEE one too!). Here it is. Recall that *cast *=
>> unpack . pack maps equal-sized objects onto each other bitwise. Again,
>> I'll
>> remove the sign bit first before even thinking about it, in order to
>> simplify this problem. That already guarantees symmetrical behavior
>> around
>> zero, for better or worse:
>>
>>
>>
>>
>>
>>
>> *myFloatToInt :: (Bool,Int8,Word23) -> IntmyFloatToInt (_,0,0) =
>> 0myFloatToInt (True,e,m) = - myFloatToIntPos (e,m)myFloatToInt
>> (False,e,m)
>> = myFloatToIntPos (e,m)-- **needs Word/Int to have more than 24 bits*
>>
>>
>>
>>
>>
>> *myFloatToIntPos :: (Int8,Word23) -> IntmyFloatToIntPos (e,m) = if e-127
>> >
>> 23 then m' .<<. fromEnum
>> ((e-127)-23) else m' .>>. fromEnum (23-(e-127))
>> where m' = cast(setBit (zeroExtend m) 23) :: Int*
>>
>> (A late reminder that .<<. is shiftL and .>>. is shiftR). Test:
>>
>>
>>
>>
>> *> myFloatToInt (mydecodeFloat 98.7)98> myFloatToInt (mydecodeFloat
>> (-101.1))-101*
>>
>> That's what I mean by *symmetrical *truncation towards zero. One might
>>> *myencodeFloatPos :: (Int8,Word23) -> Float*
>>> *myencodeFloatPos (zExp,zFrac) = result *
>>> * where result = cast((zeroExtend(cast zExp) .<<. 23) .|. zeroExtend
>>> zFrac :: Word32)*
>>>
>>> By "*.<<.*" I mean *shiftL*.
>>>
>>> That will synthesize. Haskell float to/from whatever transforms probably
>>> won't, since they will have been written as recursive functions.
>>>
>>> Sorry about the unnecessary complication originally in the encode
>>> function.
>>>
>>> Further, one can avoid the haskell negation of floats that I used in
>>> the
>>> top level encoding function by setting the sign bit in the underlying
>>> IEEE
>>> layout:
>>>
>>>
>>>
>>> *myencodeFloat :: (Bool,Int8,Word23) -> FloatmyencodeFloat
>>> (True,zExp,zFrac) =*
>>> * unpack(setBit (pack(myencodeFloatPos(zExp,zFrac)))
>>> 31) -- **was "- stuff"*
>>> *myencodeFloat (False,zExp,zFrac) = myencodeFloatPos(zExp,zFrac)*
>>> *myDivFloat :: (Bool,Int8,Word23) -> (Bool,Int8,Word23) ->
>>> (Bool,Int8,Word23)myDivFloat (s1,e1,m1) (s2,e2,m2) = (s,e,m)*
>>>
>>>
>>> * where s = s1 /= s2 :: Bool*
>>> * e = (e1 - 127) - (e2 - 127) + 127 :: Int8*
>>>
>>>
>>>
>>> * m1' = setBit (zeroExtend m1) 23 :: Word48 --
>>> caculate
>>> in 48b m2' = setBit (zeroExtend m2) 23 :: Word48 *
>>>
>>> * m = truncateB ((m1' .<<. 23) `div` m2') :: Word23*
>>> Test:
>>> *> myencodeFloat(myDivFloat (mydecodeFloat 1.3) (mydecodeFloat 4.5))*
>>> *0.28888887 *
>>> *> 1.3 / 4.5 :: Float*
>>> * 0.28888887 *
>>>
>>> I'm truncating, not rounding. Boo hoo. IEEE probably allows either.
>>> Somebody else can read the standard and tell me. I'll rely on supposing
>>> the
>>> standard accommodates all existing implementations at the time it was
>>> drawn
>>> up, and at that time some vendors did it the least complex way and saved
>>> on
>>> adding a half-something somewhere in there. So sue me. I'll fix if reqd.
>>>
>>> For help in converting to/fro, here's how to turn an Int into an IEEE
>>> float. Recall that *cast* = unpack . pack maps equal bitsize things onto
>>> each other, such as Signed onto Unsigned (Int onto Word) and back again.
>>>
>>> *-- **works on up to 128 bit ints (could use Integer instead of Int)*
>>>
>>>
>>>
>>>
>>> *myIntToFloat :: Int -> (Bool,Int8,Word23)myIntToFloat x = (x <
>>> 0,e,m) where (e,m) = myIntToFloatPos (abs x)-- **only on
>>> positive ints, up to 127 bit posints at least*
>>>
>>>
>>>
>>>
>>>
>>> *myIntToFloatPos :: Int -> (Int8,Word23)myIntToFloatPos 0 =
>>> (0,0)myIntToFloatPos x = if n < 23 then (127+toEnum
>>> n,truncateB(cast x .<<. (23-n))) else (127+toEnum
>>> n,truncateB(cast x .>>. (n-23))) where n = ff1 x --
>>> **index
>>> of highest set bit*
>>>
>>>
>>> I used this helper function to find the position of the most significant
>>> bit in an Int, or whatever:
>>>
>>> -- *highest set bit number*
>>>
>>>
>>>
>>> *ff1 x = case findIndex (/=0) (bv2v (pack x)) of Just i ->
>>> finiteBitSize x - 1 - fromEnum i Nothing -> -1 -- for x == 0
>>> !!*
>>> Test:
>>>
>>>
>>> *> myencodeFloat(myIntToFloat (-8000001))-8000001.0*
>>>
>>> That looks OK.
>>>
>>> I'll need to compare floats. Comparing with zero would do if I had done
>>> addition and subtraction already, but I haven't, so I'll do the float
>>> against float compare. Only one comparison is needed, as one can swap
>>> sides and use not and && to get the others. This is basically alphabetic
>>> ordering on the IEEE triples, with sign thrown in. I'll delegate the
>>> comparison to positive against positive, after dealing with the signs:
>>>
>>>
>>>
>>> *myLtFloat (s1,e1,m1) (s2,e2,m2) = case undefined of _ | s1 &&
>>> not s2 -> True -- **neg < pos*
>>> * _ | not s1 && s2 -> False -- **pos <
>>> neg*
>>> * _ | not s1 && not s2 -> myLtFloatPos (e1,m1) (e2,m2) -- **pos <
>>> pos*
>>> * _ | s1 && s2 -> myLtFloatPos (e2,m2) (e1,m1) -- **neg <
>>> neg*
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> *myLtFloatPos (e1,m1) (e2,m2) = case undefined of _ | e2 - e1 >
>>> 0 -> True _ | e2 - e1 < 0 -> False _ | m2 > m1
>>> -> True _ | m2 <= m1 -> False*
>>> Test:
>>>
>>>
>>> *> myLtFloat (mydecodeFloat 1.3) (mydecodeFloat 4.5)True*
> <
https://groups.google.com/d/msgid/clash-language/070d6426-522a-45e9-a041-f92560826b6dn%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
> --
> You received this message because you are subscribed to the Google Groups
> "Unum Computing" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to
unum-computin...@googlegroups.com.
> To view this discussion on the web visit
>
https://groups.google.com/d/msgid/unum-computing/CAMpdyDYEgaeXAavLuiqa0JEpSryRqa6_XifB4ua%2BVz2A0-1gPQ%40mail.gmail.com.
>