<jupyter_start><jupyter_text>\title{Floating Point (Q) format and Floating Point Rounding in myHDL}\author{<NAME>}\maketitle  Referanceshttps://timetoexplore.net/blog/fixed-point-numbers-in-verilog<jupyter_code>from myhdl import *
from myhdlpeek import Peeker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sympy import *
init_printing()

from bitstring import BitArray

#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information myhdl, myhdlpeek, numpy, pandas, matplotlib, sympy, bitstring
#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText
#4 bit int, 4 bit float
Q=(4,4)
Qlen=Q[0]+Q[1]
Qscale=2**(Q[1]); Qscale<jupyter_output><empty_output><jupyter_text>Postive Addition<jupyter_code>a=3.6250; b=4.0625
c=a+b; c
aQ=int(a*Qscale); bQ=int(b*Qscale)
f'aQ:{aQ}; bA:{bQ}'
aQBV=intbv(aQ)[Qlen:]; bQBV=intbv(bQ)[Qlen:]
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'
cQ=aQBV+bQBV; cQ
c==cQ/Qscale
class AddPosTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]; self.Qmax=2**self.Qlen
        self.Qscale=2**self.Q[1]
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndAdd(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1pV2=(self.V1+self.V2).round(decimals=self.Q[1])
        self.V1pV2Q=(self.V1pV2*self.Qscale).astype(int)
        if (self.V1Q+self.V2Q)<self.Qmax:
            self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
            self.bTV=np.append(self.bTV, self.V1); self.bTVQ=np.append(self.bTVQ, self.V1Q).astype(int)
            self.cK=np.append(self.cK, self.V1pV2); self.cKQ=np.append(self.cKQ, self.V1pV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndAdd()
        #print('Done')
@block
def AdderBehaverial(a, b, c):

    @always_comb
    def logic():
        c.next=a+b
        
    return instances()
Peeker.clear()
a=Signal(intbv(0)[Qlen:]); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:]); Peeker(b, 'b')
c=Signal(intbv(0)[Qlen:]); Peeker(c, 'c')

TVG=AddPosTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ


DUT=AdderBehaverial(a, b, c)

def Adder_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):
            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

            
sim=Simulation(DUT, Adder_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()
PAOData=Peeker.to_dataframe()
#load in the source floating values
PAOData['aTV']=aTV; PAOData['bTV']=bTV
#get the predicted floating Point Sum
PAOData['aTV+bTV']=aTV+bTV
#get the predicted fixed point sum
PAOData['aQ+bQ']=aTVQ+bTVQ
#reorder
PAOData=PAOData[['a', 'aTV', 'b', 'bTV', 'aTV+bTV', 'aQ+bQ',  'c']]
#load the sourced Qed sum
PAOData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
PAOData['cdQ']=PAOData['c']/Qscale
#load the sourced floting sum
PAOData['cKTV']=cKTV
PAOData
#dataframe of error measures
PAODataErr=pd.DataFrame()
PAODataErr['aQ+bQ_c']=np.abs(PAOData['aQ+bQ']-PAOData['c'])
PAODataErr['c_cKTVQ']=np.abs(PAOData['c']-PAOData['cKTVQ'])
PAODataErr['cdQ_cKTV']=np.abs(PAOData['cdQ']-PAOData['cKTV'])
PAODataErr['c_cKTVQ__cdQ_cKTV']=np.abs((PAODataErr['c_cKTVQ']/ Qscale)- PAODataErr['cdQ_cKTV'])
PAODataErr
PAODataErr.describe()
DUT.convert()
VerilogTextReader('AdderBehaverial');<jupyter_output>***Verilog modual from AdderBehaverial.v***

 // File: AdderBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:15 2018


`timescale 1ns/10ps

module AdderBehaverial (
    a,
    b,
    c
);


input [7:0] a;
input [7:0] b;
output [7:0] c;
wire [7:0] c;





assign c = (a + b);

endmodule<jupyter_text>Negative Values<jupyter_code>a=3.6250; aQ=int(a*Qscale);a, aQ
b=-1.5; bMagQ=int(abs(b)*Qscale); bMagQ
bMagQBV=bin(bMagQ, Qlen); bMagQBV
bQBVComp="".join([str(int(not(int(i)))) for i in bMagQBV]); bQBVComp
bQComp=int(bQBVComp, 2); bQComp
bQ2Comp=bQComp+1; bQ2Comp
bQBV2Comp=bin(bQ2Comp, 2); bQBV2Comp
(BitArray(bin=bQBV2Comp).int)/ Qscale
aQBV=intbv(aQ)[Qlen:].signed()
aQBV, bin(aQBV, Qlen), aQBV.min, aQBV.max
bQBV=intbv(int(b*Qscale))[Qlen:].signed()
bQBV, bin(bQBV, Qlen)
bQBV2Comp==bin(bQBV, Qlen)
a+b
c=aQBV+bQBV; c, c/Qscale
class AddPosNegTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]
        self.Qmin=-(2**(Qlen-1)); self.Qmax=2**(self.Qlen-1) -1
        self.Qscale=2**self.Q[1]
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.Sign=np.random.randint(2)
        if self.Sign==1:
            self.V2=-self.V2
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndAdd(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1pV2=(self.V1+self.V2).round(decimals=self.Q[1])
        self.V1pV2Q=(self.V1pV2*self.Qscale).astype(int)
        
        check=self.V1Q+self.V2Q
        if self.V1Q>self.Qmin and self.V1Q<self.Qmax:
            if self.V2Q>self.Qmin and self.V2Q<self.Qmax:
                if check>self.Qmin and check<self.Qmax:
                    self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
                    self.bTV=np.append(self.bTV, self.V2); self.bTVQ=np.append(self.bTVQ, self.V1Q).astype(int)
                    self.cK=np.append(self.cK, self.V1pV2); self.cKQ=np.append(self.cKQ, self.V1pV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndAdd()
        #print('Done')  


Peeker.clear()
a=Signal(intbv(0)[Qlen:].signed()); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:].signed()); Peeker(b, 'b')
c=Signal(intbv(0)[Qlen:].signed()); Peeker(c, 'c')

TVG=AddPosNegTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ


DUT=AdderBehaverial(a, b, c)

def Adder_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):
            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

            
sim=Simulation(DUT, Adder_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()
AOData=Peeker.to_dataframe()
#load in the source floating values
AOData['aTV']=aTV; AOData['bTV']=bTV
#get the predicted floating Point Sum
AOData['aTV+bTV']=aTV+bTV
#get the predicted fixed point sum
AOData['aQ+bQ']=aTVQ+bTVQ
#reorder
AOData=AOData[['a', 'aTV', 'b', 'bTV', 'aTV+bTV', 'aQ+bQ',  'c']]
#load the sourced Qed sum
AOData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
AOData['cdQ']=AOData['c']/Qscale
#load the sourced floting sum
AOData['cKTV']=cKTV
AOData
#dataframe of error measures
AODataErr=pd.DataFrame()
AODataErr['aQ+bQ_c']=np.abs(AOData['aQ+bQ']-AOData['c'])
AODataErr['c_cKTVQ']=np.abs(AOData['c']-AOData['cKTVQ'])
AODataErr['cdQ_cKTV']=np.abs(AOData['cdQ']-AOData['cKTV'])
AODataErr['c_cKTVQ__cdQ_cKTV']=np.abs((AODataErr['c_cKTVQ']/ Qscale)- AODataErr['cdQ_cKTV'])
AODataErr
AODataErr.describe()
DUT.convert()
VerilogTextReader('AdderBehaverial');<jupyter_output>***Verilog modual from AdderBehaverial.v***

 // File: AdderBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:24 2018


`timescale 1ns/10ps

module AdderBehaverial (
    a,
    b,
    c
);


input signed [7:0] a;
input signed [7:0] b;
output signed [7:0] c;
wire signed [7:0] c;





assign c = (a + b);

endmodule<jupyter_text>Multiblication<jupyter_code>#Q4.4 *Q4.4 -> Q8.8
Q2=(Q[0]*2, Q[1]*2)
Q2len=Q2[0]+Q2[1]
Q2scale=2**(Q2[1]); Q2scale
a=3.2500; aQ=int(a*Qscale)
b=-2.065; bQ=int(b*Qscale)
aQ, bQ
bin(aQ, Qlen), bin(bQ, Qlen)
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'
abQ=aQBV*bQBV; abQ
abdQ=abQ/ Qscale; abdQ, ab
abdQ=abQ/ Q2scale; abdQ,ab
class MultPosNegTVGen():
    """
    Class to generate postive random numbers to be Qed for testing 
    """
    def __init__(self, Q, N):
        """
        Take in arguments and create output holds
        Args:
            Q(tuple): Q notation tuple where Q[0] is int bit len and Q[1] is
            dec bit len
            N(int): number of values to generate
        """
        self.Q=Q; self.N=N
        self.Qlen=self.Q[0]+self.Q[1]
        self.Qmin=-(2**(self.Qlen-1)); self.Qmax=2**(self.Qlen-1) -1
        self.Qscale=2**self.Q[1]
        
        #Q4.4 *Q4.4 -> Q8.8
        self.Q2=(self.Q[0]*2, self.Q[1]*2)
        self.Q2len=self.Q2[0]+self.Q2[1]
        self.Q2min=-(2**(self.Q2len-1)); self.Q2max=2**(self.Q2len-1) -1
        self.Q2scale=2**(Q2[1])
        
        
        
        self.aTV=np.zeros(0); self.aTVQ=np.zeros(0)
        self.bTV=np.zeros(0); self.bTVQ=np.zeros(0)
        self.cK=np.zeros(0); self.cKQ=np.zeros(0)

    def Genrator(self):
        """
        Random Number genrator in floating point and supsequent Qed version
        """
        self.V1=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.V2=np.array((1/np.random.ranf())).round(decimals=self.Q[1])
        
        #needed to force np.random to generate a differint random num
        np.random.seed(np.random.randint(self.Qmax))
        
        self.Sign=np.random.randint(2)
        if self.Sign==1:
            self.V2=-self.V2
        self.V1Q=(self.V1*self.Qscale).astype(int)
        self.V2Q=(self.V2*self.Qscale).astype(int)
        
    def GenratorCheckAndMul(self):
        """
        Cheacks if the sum of the two randome numbers generated are going to break the Qmax
        if they do dont append to retrun holds
        """
        self.V1tV2=(self.V1*self.V2).round(decimals=self.Q2[1])
        self.V1tV2Q=(self.V1tV2*self.Q2scale).astype(int)
        check=self.V1Q*self.V2Q
        if self.V1Q>self.Qmin and self.V1Q<self.Qmax:
            if self.V2Q>self.Qmin and self.V2Q<self.Qmax:
                if check>self.Q2min and check<self.Q2max:
                    self.aTV=np.append(self.aTV, self.V1); self.aTVQ=np.append(self.aTVQ, self.V1Q).astype(int)
                    self.bTV=np.append(self.bTV, self.V2); self.bTVQ=np.append(self.bTVQ, self.V2Q).astype(int)
                    self.cK=np.append(self.cK, self.V1tV2); self.cKQ=np.append(self.cKQ, self.V1tV2Q).astype(int)
    
    def MakeTVs(self):
        """
        Automates the generating, testing and appending to make the TVs
        
        Returns:
            self.aTV(np.array): floating point numbers for a
            self.aTVQ(np.array): fixed point Qed from self.aTV
            self.bTV(np.array): floating point numbers for b
            self.bTVQ(np.array): fixed point Qed from self.bTV
            self.cK(np.array): known floating point rounded sum of self.aTV, self.bTV
            self.cKQ(np.array): known fixed point Qed from self.cK

        """
        while len(self.aTV)<=self.N:
            self.Genrator()
            self.GenratorCheckAndMul()
        #print('Done')  


@block
def MultiBehaverial(a, b, c):

    @always_comb
    def logic():
        c.next=a*b
        
    return instances()
Peeker.clear()
a=Signal(intbv(0)[Qlen:].signed()); Peeker(a, 'a')
b=Signal(intbv(0)[Qlen:].signed()); Peeker(b, 'b')
c=Signal(intbv(0)[Q2len:].signed()); Peeker(c, 'c')

TVG=MultPosNegTVGen(Q, 100); TVG.MakeTVs()
aTV=TVG.aTV; aTVQ=TVG.aTVQ
bTV=TVG.bTV; bTVQ=TVG.bTVQ
cKTV=TVG.cK; cKTVQ=TVG.cKQ

DUT=MultiBehaverial(a, b, c)

def Multi_TB():
    
        
    @instance
    def simules():
        for i in range(len(aTVQ)):

            a.next=int(aTVQ[i])
            b.next=int(bTVQ[i])

            yield delay(1)
        
        raise StopSimulation()
    
    return instances()

            
sim=Simulation(DUT, Multi_TB(), *Peeker.instances()).run()
Peeker.to_wavedrom()
MultiData=Peeker.to_dataframe()
#load in the source floating values
MultiData['aTV']=aTV; MultiData['bTV']=bTV
#get the predicted floating Point Sum
MultiData['aTV*bTV']=aTV*bTV
#get the predicted fixed point sum
MultiData['aQ*bQ']=aTVQ*bTVQ
#reorder
MultiData=MultiData[['a', 'aTV', 'b', 'bTV', 'aTV*bTV', 'aQ*bQ',  'c']]
#load the sourced Qed sum
MultiData['cKTVQ']=cKTVQ
#de Q the testbench gen sum 
MultiData['cdQ']=MultiData['c']/Q2scale
#load the sourced floting sum
MultiData['cKTV']=cKTV
MultiData
#dataframe of error measures
MultiDataErr=pd.DataFrame()
MultiDataErr['aQ*bQ_c']=np.abs(MultiData['aQ*bQ']-MultiData['c'])
MultiDataErr['c_cKTVQ']=np.abs(MultiData['c']-MultiData['cKTVQ'])
MultiDataErr['cdQ_cKTV']=np.abs(MultiData['cdQ']-MultiData['cKTV'])
MultiDataErr['c_cKTVQ__cdQ_cKTV']=np.abs((MultiDataErr['c_cKTVQ']/ Q2scale)- MultiDataErr['cdQ_cKTV'])
MultiDataErr
MultiDataErr.describe()
DUT.convert()
VerilogTextReader('MultiBehaverial');<jupyter_output>***Verilog modual from MultiBehaverial.v***

 // File: MultiBehaverial.v
// Generated by MyHDL 0.10
// Date: Sat Aug 25 17:54:33 2018


`timescale 1ns/10ps

module MultiBehaverial (
    a,
    b,
    c
);


input signed [7:0] a;
input signed [7:0] b;
output signed [15:0] c;
wire signed [15:0] c;





assign c = (a * b);

endmodule<jupyter_text>Trunction (Unsighned)<jupyter_code>#Q4.4 *Q4.4 -> Q8.8
Q2=(Q[0]*2, Q[1]*2)
Q2len=Q2[0]+Q2[1]
Q2scale=2**(Q2[1]); Q2scale
a=3.2500; aQ=int(a*Qscale)
b=2.0625; bQ=int(b*Qscale)
aQ, bQ
#bin(aQ, Qlen), bin(bQ, Qlen)
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab
aQBV=intbv(aQ)[Qlen:]; bQBV=intbv(bQ)[Qlen:]
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'
abQ=aQBV*bQBV; abQ
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))
for j in range(Q2[1]):
    Trunc=abQBV[Q2len:j]
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))<jupyter_output>11010110100 6.703125 0.0
1101011010 6.703125 0.0
110101101 6.703125 0.0
11010110 6.6875 0.015625
1101011 6.6875 0.015625
110101 6.625 0.078125
11010 6.5 0.203125
1101 6.5 0.203125<jupyter_text>Trunction (sighned)<jupyter_code>a=3.2500; aQ=int(a*Qscale)
b=-2.0625; bQ=int(b*Qscale)
aQ, bQ
#bin(aQ, Qlen), bin(bQ, Qlen)
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'
abQ=aQBV*bQBV; abQ
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))
for j in range(Q2[1]):
    Trunc=abQBV[Q2len:j].signed()
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))
for j in range(Q2[1]):
    Trunc=(abQBV>>j).signed()
    TruncDQ=Trunc/(2**(Q2[1]-j))
    print(bin(Trunc), TruncDQ, np.abs(ab-TruncDQ))<jupyter_output>100101001100 -6.703125 0.0
10010100110 -6.703125 0.0
1001010011 -6.703125 0.0
100101001 -6.71875 0.015625
10010100 -6.75 0.046875
1001010 -6.75 0.046875
100101 -6.75 0.046875
10010 -7.0 0.296875<jupyter_text>Round Half Up<jupyter_code>a=3.2500; aQ=int(a*Qscale)
b=-2.0625; bQ=int(b*Qscale)
aQ, bQ
bin(aQ, Qlen), bin(bQ, Qlen)
ab=a*b; ab
abQ=int(ab*Qscale); abQ
abdQ=abQ/ Qscale; abdQ, ab
aQBV=intbv(aQ)[Qlen:].signed(); bQBV=intbv(bQ)[Qlen:].signed()
f'aQBV: {bin(aQBV, Qlen)}; bQBV: {bin(bQBV, Qlen)}'
abQ=aQBV*bQBV; abQ
abQBV=intbv(abQ)[Q2len:].signed(); abQBV, bin(abQBV), len(bin(abQBV))
ab, floor(ab+.5), -ceiling(-ab-.5), ceiling(floor(2*ab)/2)
Round=abQBV[Q2len-1:0].signed()
RoundDQ=Round/(2**(Q2[1]))
print(bin(Round), RoundDQ, np.abs(ab-RoundDQ))<jupyter_output>100101001100 -6.703125 0.0<jupyter_text>`{ {(OWID){1'b0}}, 1'b1, {(IWID-OWID-1){1'b0}} }`, .5 `i_data[(IWID-1):0]+ { {(OWID){1'b0}}, 1'b1, {(IWID-OWID-1){1'b0}} }`, x+.5  `w_halfup[(IWID-1):(IWID-OWID)]`, floor(x+.5)<jupyter_code>concat(intbv(0)[8:], True, intbv(0)[16-8-1:])
PointFive=intbv(int(.5*Q2scale))[16:]; PointFive, bin(PointFive, 16)
abQBVP5=intbv(abQBV+PointFive)[16:].signed()
abQBVP5
abQBVP5=abQBVP5[Q2len-1:Q2len-Qlen].signed(); abQBVP5
abQBVP5, floor(ab+.5)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1658351626421872, 'fraction_numerical': 0.039263620035920974, 'mean_word_length': 3.2630795406210122, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '419035', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 9090, 'n_tokens_neox': 8492, 'n_words': 1518, 'path': 'myHDL_DigitalSignalandSystems/FloatingNumAndRounding/QRound.ipynb', 'repo_name': 'PyLCARS/PythonUberHDL', 'size': '20053'}