 Hey guys, welcome back skit zone series episode 7 topic today is fractions great topic actually a bit of a gateway drug topic because I really can't think of very many engineering problems that don't involve Fractions or continuous variables like 1.3 Negative 5.6 pi square root of 3, you know the numbers between the numbers So yeah today's episode is gonna be about how we can represent fractions different ways to do that some of the pros and cons of each Way and yeah, we'll go from there. So Let's get into it So here is the starting off just with very basics here just for refresher it leads into future content So I'm doing it this way so map Needs to tell Dora that the castle is five kilometers north But he doesn't remember the Mexican word for five, but thankfully Dora understands binary encoding And so typically how we would represent five in binary as we count from right to left The lowest bit would be on the right That'd be two to the zero and we would basically populate this number Flipping these switches such that the zero from the second bit are high. So the total is five Pretty simple But it gets a little bit more complicated when you have to add more than just positive numbers into the mix so Positive whole number I should say So here's the next problem statement map Got a little bit turned around and actually the castle is 5k south Not north and he doesn't know the Chilean word for south and Dora is expecting a distance nor So how can we communicate negative five? To Dora a couple different options Sometimes it's best to have a sign bit just have a bit That's maybe on the far left the highest bit most significant bit or anywhere you want to be really just that indicates that this number is negative So basically if this was zero This would be positive five and if it's one it would be negative five. That's the that's the approach You could also have a sign integer Via some kind of complement. So typically the way the boomers have this up is basically You divide your range in half. So you have half the positive numbers and half the negative numbers That you would otherwise had all positive numbers now You have half positive half negative and basically you start counting that the biggest number one one one one one one one All ones is negative one and then you just kind of count backwards from that and there are tricks like two's complement and whatever else it's called to do that kind of stuff, but Ultimately, you just basically counting backwards from the biggest number and the biggest number is negative one That's so everything wraps around, you know And that's why addition and subtraction still work when you have sign integers using like this kind of complement So that that's cool, right? Otherwise you could have some kind of custom data type Maybe you want to be able to encode other directions too Maybe map wants to encode east and west as well as north and south and so maybe you dedicate two bits to communicating north south east and west That's an option. There's so many different ways to do things. It's all up to you That's the beauty of like little computer things that you can kind of do whatever you want No one can tell you otherwise. So pretty cool stuff Now that's negative numbers and basically the message is that you can do whatever you want with your bits You can choose. I mean if you wanted to you could make five the other way You could have the least significant bit beyond the far left All right, you could count you have everything backwards up to you Do whatever you want. I mean whatever suits your problem in hand, right? So you have so much flexibility to do whatever you need to do Next problem statement now at this point Dora map backpack, maybe boots the monkey Is that his name? They walk closer toward the castle So how can map let Dora know that they're they're closer. They're now half a kilometer away and so Well How would you do that? There's so many different ways. How would you communicate a fraction to Dora? Using just these switches on and off Well, I could think of a couple dozen options I'm gonna just show you a few here on the next two slides But there's also so many options that you could do for this So the first one might just be how about a flag how about, you know maps like you know what? I typically only give her a couple of directions in terms of distance like your GPS says, you know, you know turn turn left in 1,000 feet turn left in half a kilometer, right? There's only a few options, right? So why don't we encode every possible option as just a flag so in this case? I have a flag bit that means hey this number has flags in it and Basically, hey if the lowest bit is high that means I'm talking about half a mile for half a kilometer or whatever you're talking about half of If this bit the third bit is high that means a fifth Right so this way you keep it communicate common fractions common numbers Hey, you can even do pie this could be one over pie This could be one over e whatever numbers you want you can you can pick it's up to you, right? You can encode those things as well. So basically That's an option and maybe you want to be able to add more options. Hey, how about you maybe you imply some kind of multiplication What if you had this bit and In this bit both ones Well, maybe that means one tenth of them of a kilometer and What if this was a one and this was a one? That'd be one sixth of a kilometer. I don't know. It's just an idea. That might work Right, that's an option. You could do that. It might be a good solution for a certain problem How about option two you can just change the units, right? We're talking about kilometers here Why don't we why don't we talk about meters or? millimeters or Hectometers Half a kilometer is just five Hectometers, right? So just encode five and change the unit That works How about you count things in paces? Yeah, I mean how many steps you have to go then everything is integer, right? You don't take half a step Right, so just encode paces, right? That's what a mile is, you know mile meal, you know thousands right a thousand strides when you're running every stride is 5.28 feet, right? Hey, let's do that. Let's just encode things in terms of paces or strides. It's a good idea Option three. How about we imply some denominator? How about we whisper to Dora? Hey Dora? Take this number and divide it by some other number number how about number two So then all we have to do is pass her a one In the register and she knows hey, I'll just take half of that. I'll divide by two That's my implied denominator and some people might think okay. That's just fixed point numbers Mmm in this case it kind of is but not in general because I can pick any denominator I want I can pick three you can't do three in fixed point. I can pick pie I could have any implied denominator. I want here that kind of goes back to the meme at the beginning, you know that Yu-Gi-Oh meme Pi over one is if is a fraction, right? technically, I Just you know, I just in this case I imply a numerator, but you could do whatever you want, right? You want to encode one of these numbers? Maybe you can want to encode one and you imply pi as a numerator. That's an option Right So cool, that's an option having an implied denominator. What are some other options? There's so many options One more option would be how about an encoded fraction? How about we take different parts of the the register or of the bits and we dedicate those to numerator versus denominator So let's say the first two bits on the left our numerator and the last three are the nominators in this case I'm encoding one as a numerator and two as the denominator. So the number is a half So I can encode any number I can encode three Quarters I can encode zero Sevenths, right? I can go to any number that I want in this in this way Maybe you want to have a few more bits here for signs a few more bits me for a whole number part of it I don't know up to you. You can pick whatever you want. It's your your implementation Right another option might be fixed point. This is a very, you know common way to do stuff Maybe 40 years ago before they had floating point units in computers But it's still good to this day. Basically, you are implying usually like a power of two denominators. So In this case, you can see I've um, basically I've placed a decimal point between the first three and the last two bits So basically Normally if you go back The lowest bit was two to the zero and the fifth bit was two to the fourth But in this case, I've lost bits actually to the negative two and the highest one is two to the two And so basically I've just shifted the whole number to the left by two giving me two binary Decimal places to work with and so in this case, you know two to the one half or sorry two negative one is one half And so this number encodes one half but without any need for fractions. It's just a shifted point That's why it's called fixed point because the decimal is here and not here That's the idea and The last option might be floating point And I'll talk about that a bit in a second And so I guess the moral of the story is again, there's so many different options You couldn't have other implied expressions when you imply a square root Maybe you imply a screw on part of the fraction. Maybe you maybe you do Multiple things. Maybe you have numerator denominator and fixed point and you add everything together Maybe you have subtraction you could encode anything you want in binary That's the beauty of this anything that you can think of you can encode Just a mess of bits these seven bits are numerator and these 12 bits are you know offsets and this you can pick whatever you want It's up to you and so yeah, you can do whatever you want with your bits Now when it comes to floats, we're gonna talk about in this series I'm gonna stick prominently with double precision floating point numbers. So I'm gonna call them a float But I guess the the C programming word would be double But yeah, they're basically the same thing. So we're talking about eight byte quantities that represent Decimals like seven point three eight and the way that this works I'm not going to too much detail on this because it's you could read this Wikipedia article yourself And no way more than what I'm gonna say basically there's one bit for signs eleven bits for the Exponents and the fraction is encoded 52 bits and there's like an implied One in front. So you have basically you have to represent numbers across a huge amount of Expedits like you can't get anywhere close to this with integers. So you can get to the power of three negative 308 10 to the 10 e negative 308 and 10 e positive 308 and even down to 324 If you don't care about your precision being so good. So that's an incredible Ability to represent numbers that are super small and super huge What I don't like this is because it's almost a waste like I'm an engineer and we don't go above like 10 to the 12 In my field I work in mechanical engineering and we go down to maybe like the The 10 thousandths of an inch, but we don't go down to 10 e negative 308 So yeah, you have all this ability, but it's kind of a waste like these exponent bits. You could have used them for Precision instead you use them for shifting your number big and small So anyway, it's a cool idea and you can read all about it and we're gonna use it in a series like Almost all the time because it's so easy But there are other ways to do things that's the point of this video to show you the other ways to implement similar things to a floating point When it comes to floating point, I'm not gonna go too much into the instructions I'm just gonna leave this here for you. I might go through it right now Just a quick run over of some of the instructions that we're gonna use. We're gonna use sse to What does that stand for? Single input multiple data streaming extension to I have no idea something like that Basically, this is like the oldest version of modern floating point numbers We used to have a math core processor and you still do like for floating point stuff on your on your PC But um, no one uses that stuff anymore I'm not even sure compilers can even I have well, maybe they can it was some kind of flag But I haven't seen any compiled code generate with those like floating point instructions from the good old days usually it will generate like Sse to and new earth AVX 512 or whatever basically it's just We have 128 bit wide registers into which we can fit to 64 bit floats and new stuff And by the way, there are newer versions of this which I'm pretty sure is on your computer right now as we speak Most you have some kind of old garbage computer Like you have YMM registers, which are twice as big. There are two five six bits wide And you also have ZM registers ZMM which are five twelve I believe so you can fit so many floats into those so you can do a lot of vectorized like parallel processing of numbers and there's a bunch of cool tricks with that We're gonna stick with XMM because it's simple and this this series is not about going like The like the fastest you possibly can it's about understanding what's going on and this kind of is like laying the groundwork for all that So that's that's the point of this series So most of the instructions have come to variants. Obviously, there's add divide maximum minimum multiply square root Subtract and many others those are like arithmetic instructions and basically you would pass in like to it to either XMM registers or you pick an XM register and I'll spend our memory location and basically the idea is You know, you can add to XMM one What is an XMM to or you can? divide what's an XMM one by some quantity at this memory location the 128 bit memory location so that's kind of how that works and then the P and the S so Basically the D means double precision. There's also an S option for that I mean would that'd be like a single precision. So there's float float is four bytes double is eight bytes Or 32 bits for 64 bits. So yeah, D. I were gonna stick with doubles for everything so everything will be a D at the end for this series and So the P that means packs that means like you got two numbers in there That I want to make sure that I'm adding two at a time always right versus S S would just be the low the low double precision number so In general, we're probably just gonna stick with the S D versions of all these instructions. So we're gonna do add SD div SD max SD min SD mol SD Sd and sub SD That's pretty much the gist of it We may do some vector addition later on the series or we're gonna do you know bigger and better things But for the time being that's good enough for us And then those are arithmetic instructions and then you have a couple different ways to move things around So move SD is a way that you'd move a value between XM registers or you might move a value from memory into register and if you wanted to Move a value from like register Rax Xmm 0 what you'd say you say move Q Xm 0 Rax and that would basically move the quad word from Rax into Xm 0 So that would also be a valid option But yeah, that's how you move stuff and the last kind of a really important one there's a few others like not and or and stuff but Come is D. So basically this is just a compare instruction for Scalar like single scalar precision numbers. So you can compare quantities. So let's say you had Like five in this XM register and then four in this one You can compare five and four and then the certain flags would be set That's that you could jump to a label in your code. So you can then like check for tolerances I have an example that I'll show you in a few minutes. We're gonna use the commis Instruction, so you'll see then how it works. So yeah, this is pretty much Everything we're gonna do in terms of the programming floating point in this entire series. This one slide covers that all right Sort of the pros and cons. So I got three categories here. Oh, can you see the bottom piece? Yeah, you can So I got floating point I have fixed point and I have a custom implementation Which could be like any number of the things we talked about before like fractions or flags or whatever so Floating point is a great because it just works like you can just plug in chug numbers in Nazem the assembler already knows how to generate a floating point numbers You can define a quad word like 1.5 and it will automatically convert that to that really complex looking Gobbledy cook like this like it will automatically generate that for you. So It's really cool. So it just everything just works. You can you can add numbers like it's so easy to do Also, there's a really fast hardware implementation of really complex things So like for example, square root sd to that instruction over here spirit sd that That's a hardware implementation that it would be really hard to implement that in software and also really slow So if you want to implement square root for fixed point numbers and custom numbers, you might be in trouble So but yeah, it exists for pointing point. Also, you can easily vectorize things and floating point You have those single instruction multiple data or whatever it's called so you can be really fast You can do operation fun, you know two four eight things at once more if you use single precision, right? The problems are hey, there's a minimal clever tricks like there's a bunch of cool tricks You can do with fixed point numbers You can shift fixed point numbers to divide them by powers of two, right or multiply them by powers of two things like that Little tricks up your sleeve So yeah, that's that's an issue Also, you have to jump through hoops to do simple things like even printing a number out to the screen Folding point number. It's not trivial. I have to implement a whole like law natural log and log base 10 Algorithm I want to show you that right now. It's just not easy It's super easy to implement printing a fixed point number. It's just a Super easy just powers of two so you can do it like in your head and super easy to print out fractions and stuff It's just numerator denominator integers floating point you got to figure out how to parse this thing or or something like that or you have to Actually do math and constantly be recomputing. That's what we're gonna be doing in this video so yeah, it's just a big mess and Also, I would say it's the least memory efficient option You're wasting those 11 bits on exponent when normally your problems at least in my feel are very well-bounded We don't go above 10 to the 12 10 to the 15th Maybe and so we can do everything in terms of fixed point with way better precision on on that end Now fixed point though it kind of just works certain things work Obviously fixed point is just an integer implementation so You can add point five and point five in the same way that you would add one in one and it just works So that's kind of cool There are a lot of clever tricks you can do for fixed point There's a sneaky math tricks and also there are It's a pretty efficient use of bits because there's no waste on that 11-bit exponent that you have for floating point Now some things can be vectorized in fixed point not everything but some things can The problem is you don't be I don't have the ability to represent really small numbers unless you pick Like you can't have both small really small numbers and really big numbers in the same math It won't work if you don't have the ability to do that and also you'd still have to jump through some hoops to do simple things Now what about a custom implementation like a fraction or something like that? This is super application specific so you can pick like the perfect one for the job You can have it be super fast because it's all going to be like tricks You have in it maybe an implied denominator that you don't have to even define because you know what it's going to be like So many shortcuts you can take it's probably a more efficient use of bits in those cases and there are a huge number of Clever arithmetic tricks you can do and also you can encode other stuff like remember when we had map encoding North East South and West you could encode additional information into your You know bit stream or whatever you want to call it into your register for additional characteristics of whatever you're talking about the problem is you have to implement it yourself Every time you can't just plug in chug like floating point you had to implement this each time for a unique problem and then You may not be able to use those fast hardware implementations like a square root like I mentioned and also Convoluted stuff like you had some really complicated, you know bit pattern like these are numerator This is the denominator. This is the flag. It's just a shift. This is the fixed point like everything's scrambled together It would probably be slow It would be cool, but it would probably be very slow. So There's pros and cons to all these different three you can pick the one for the job and People will say oh floating point is the best. It's the fastest people will like we would leave in smack talk fixed point I've noticed on forums. It's like are you an idiot? So I have a speed test. I'm gonna show you guys Basically, I'm sure you guys can sell me get rid of this you can see there we go So I have wanted a simple bisection algorithm like you know like a root finding type thing to compute square root of 2 I Did the same exact implementation on a fraction implementation? So I did a fractional number representation I did a fixed point Implementation I did a floating point information and I use the same Alorithm the same memory accesses the same alignment Everything is like copy and paste exactly the same and you'll see and I can show you this you know in a second Or you can run yourself on your machine and you can see The fraction runs the fastest by quite a bit I did a hundred million iterations of computing square root of 2 with the bisection algorithm to I think it was like seven or eight decimal places Within 2.35 seconds it was 2.5 seconds for a fixed point implementation and then lastly floating point Way behind like three times a slow Even with fancy tricks like this I was I was unable to get even close to the other two implementations So it's not always the fastest. Yes, you can vectorize it. Yes, you can parallelize it. Yes You can just plug in chug. Yes, it has these hardware accelerated type Instructions, but it won't always be the fastest for the job at hand. There's just one I want to let you guys know that maybe it is sometimes But maybe not all the time. That's what I'm trying to say. All right, so in this Video I'm gonna talk about a few different examples. I'm just gonna brush through them because it's so much stuff I can't even It would take me an hour So we're talking about printing floats as well as printed them with scientific notation Also printing a fixed point number as well as some speed tests that I just showed you before So let's hop into the code right now I hope you guys can see so Here goes examples. It's an example seven in the soy hubs depository. So I'm gonna get right into the Let me think how should I do this Let's go to the speed test first actually so let's go to example D that's this speed speed test with floats. So let me open up the code for you. Let me show you how this works So I have Basically an algorithm here called floating point bisect. That's just the bisection algorithm with floats So you can see here. These are those floating point instructions that I mentioned before here You can say I'm moving values. So I'm using XMM one XMM two for the bounds of the bisection algorithm You know, that's how you do it. You have two bounds and you move them in halfway each time You iterate through it until you converge on it on a tolerance that you set. So here you can see I'm checking the bounds I'm moving the upper bound into the XMM three stretch tracking off the Lower bound and then I'm comparing it versus the tolerance and if we're below it. I say we're done. You can return Here you can see I'm in I have the algorithm implemented So I'm using move add multiply Etc. Instructions to do that. I won't go through the details of the algorithm. You can figure that out yourself and Yeah, when I return I I basically loop this a hundred million times and then I print out the float so if I save that and I Let me just compile that first now. I have a binary that I can run me time the binary As you can see how long it takes in real time So Yeah, a hundred million implementation hundred million iterations. We're going down. I think it was um It was You can see it took six point eight seconds to run. I was going to a tolerance of this So whatever that value is and I mentioned before that you can define numbers in Nazm in floating point sense. All you have to do is this so you want to define the number one You just say dq that means define quad word one point. Oh, you can't just do one That would be just the integer one you have to do One point now and also protip you can't just do like Point five if you wanted to do point five you couldn't do it So I think that's a label because labels start with the point So you'd have to do zero point five, but anyway One point zero and then you could define a tolerance zero point zero zero zero zero one, etc. So that's how that works No big deal, let's go to the other examples here Was it E for the fixed speed test? Now this code I'll show you how I implemented the fixed point number. So here you can see I have these weird definitions I have a quad word of like what's that 16 million and 33 million. What is this? Basically, it's just one shifted 24 and one shifted 25 So I basically I said hey my fraction is going to be 24 bits and then the other 40 bits are going to be my integer part of the number the decimal point is not the right It's 20 bits in from the right or 24 bits in from the right I should say and yeah, it's the same algorithm, but the beauty of this is that you can see it's all integer instructions. There's no SD We're just moving integer values and we're subtracting them and adding them and here we see we can shift them because this is one of those Those tricks right I can shift the integer right or left to basically do division by two So yeah, it's an application specific cheat code that we can implement here Anyway, that's that same story same algorithm same alignment see the align directives there That's basically helps the code go a little bit faster. I won't talk about that in this video if I run this oops Mr. Compile and then I have a binary and then I Time that binary you can see it will be presumably a little bit faster here He says 2.6 seconds so way faster four seconds faster than before Same implementation same tolerance, right? Look at the code the tolerance here Well, I guess I didn't didn't show you but it's it's the same level of tolerance here Tolerance fixed one so basically We've now shifted a decimal point 24 to the left well This means even with that 24 decimal point shift one is our tolerance. So one shifted right 24 would be our tolerance So it's a small fraction So that's cool Let's go to the other example that was f this is a fractional implementation So let me show you how this works. Let's look at the code in This case. I don't have any memory. I'm not access again every everything's happening in registers So I basically have a register for numerator and for denominator. I won't get into the details But here's the algorithm you can see how it's very like weird and condensed and just like we're using add-ins Shifting as opposed to multiplying. It's all wonky It's just an application specific solution to the problem, right? So if I close this Run it to compile. Oops. I keep doing that Now I have a binary to run if I time that binary It should be faster than even the fixed point you can see here It's just a shred of a second faster So yeah, you can see there's different ways to solve problems and maybe floating point isn't the fastest way for every problem Maybe it is for some problems. Maybe not for other problems So, yeah Now let's talk about some other things. So in this folder. I also have stuff to print numbers out So let me talk about printing floats out. Let me just run the code just to begin with here As it's it's so much stuff so Let me just run the code Here you can see I'm printing out like basically the number is one two three four Point five six seven eight nine and I'm just printing it out with different amounts of significant figures and different amounts And then I'm shift. I'm dividing it by ten every time. So this first row is that number With I think it's nine significant bits then eight seven six five four three two and one and by bits I mean digits. I don't mean bits is in zero and one. I mean I mean digits So nine significant digits in base ten You can see with eight digits. I rounded that eight there to a nine Seven significant digits. I run that seven there to an eight, etc Pretty cool, right? And then I divided by ten. You kind of can see how these things all Generate and it's not easy if this is a very complicated algorithm I think when I first did this it took me a month to implement this a month So I'm not gonna talk about that all in this video I'm gonna talk about maybe a few things here and there but not the full details and then at the bottom the hardest part is Is base ten numbers like I don't know why I do know why I'm not gonna explain it But the numbers multiples powers of ten are like we're kind of a lot harder. You have to use a Lookup table to help you with these ones because it's just you might have a little bit of Inaccuracy and then it won't count like if you have if you're one bit off It won't count will be a nine point nine, right and everything will be messed up. So I also got the bottom here We have Special cases so in floating point numbers to check the Wikipedia article There's a couple special numbers plus or minus zero as well as plus minus infinity and then man man stands for not a number So yeah, that's You know what you could have as other options as well and this print routine can handle all possible numbers So positive numbers negative numbers special numbers everything everything works out Let's go into the code Actually, let me open up the other other stuff too. So code and then Let's open up the print float As well as oh my god, this is so bad. I should have done this before live math expressions log Okay Yeah, it's it's just not easy. I'll tell you right now. It's not easy. So I have a let me go to the actual code first So in this code, I'm basically just looping through different numbers I'm just calling this function print float with a float in x of m zero So and then a number of sig figs in rsi. So here's that function print float again It takes in a file descriptor to print out to you it takes the number in x of m zero and then it also takes the Number of digits that you care about Let me say nine or seven or whatever in rsi And it's not easy. You can see we're including a function right off the bat. We're including this log base 10 function And that's to figure out the power of the number So what's the log base 10 function? this is a Basically it uses a lookup table or a Taylor series approximation to compute the power of a number See how this is getting way too complicated Simple things are just so hard in floating point. And so here I have this massive Lookup table of all the powers of 10 just in case you put one in massive lookup table and then I got In the case where it's not in the lookup table You eventually have the option to call log base e so natural log That is this function here and this is basically we have algorithms for Taylor series for the Natural logarithm and so we're basically solving for natural logarithm and then converting it back with the inverse log Of 10 etc. It's just a huge mess. Look at the code if you want And it's just it's just so much Garbage and you have big numbers. You have small numbers. You have medium sized numbers. It's just not easy So I won't get into too much if you don't about that You can look it up and you can have the code. The code is yours public domain Take it and run with it. I don't care So that works now. What about the scientific notation so I have another copy of that same code That same like thing with a Scientific notation based solution because as engineers we tend to have this most of the time here You can see I've got the same numbers as before just with this e notation That means times 10 to the power of so long story short It's just the same stuff with exponential in a notation in it. Okay, cool So let me go to the Last example and that was printing out the Fixed numbers. So that's example c Of course, I can't open a folder in bim And do anything useful. So I should have gone in there like this. I'm so stupid Okay, here you can see I want to first show you the number that I've picked for fixed point I've picked this dot x memory location to contain two bytes Actually, when I loaded it's going to have eight bytes, but the low byte is going to be this fraction 0x 0 1 and I'm implying it the denominator of 8 here That's the number of bits that I don't that are not integer bits. They're bits for the for the fraction And so this basically encodes as 1 over 2 to the 8th As the fractional part and then I have 0x 8 0 that byte encodes 128 And so this quantity is 128 and One 256th That's the fixed point representation assuming you have an offset of that fixed point of eight bits And basically how this works is I basically just um I load that into a register and I print it out and then I divide it by two 17 times And I printed out every time. So let's run that and see how it looks So the first number is that number. It's 128 plus 1 over 256 and again, this is this is not hard This implementation is literally just what's the integer part and what's the fraction part In fact, I'm going to open it up for you. So you can see how much easier this is than the floating point Just to get your mind in the right zone here So, um That's in lib IO print fixed Of course, I'm an idiot as usual So this print routine literally it takes the value the value in rsi With with an implied denominator in rdx And then it just literally prints integer part prints the plus symbol and prints the numerator prints the division symbol and prints denominator It's not hard compared to the log base 10 lookup table Crap, this is way easier, right? So yeah, I run this you can see That number then that number divided by two just shifts the whole thing to the right by one bit and you can see our fraction Got killed it got shifted out of the number So you can see we got 128 64 32 16 8 4 2 1 0 with now we have half of one And you can see again, we go down down the list, right? And now let's show you with negative numbers just really quick. It's very simple Actually first, let me show you with um multiplying by two instead of dividing by two shifting left instead of right You can see our first number and then you can see every number is twice as big right Let's go back in the code Put it back the way it was now. Let's do negative numbers So that same expression also works for negative numbers that same representation You can see our number negated here. You can see it being shifted by Down every single time and you can see just because the way rounding works um It actually rounds up every time as opposed to being rounding down but that's just how negatives work in in binary so Pretty cool stuff and then last day, let's let's turn back on the multiply by two thing just because You can see this number growing and growing and growing bigger and bigger and bigger. So yeah, but that out of the way, um I'm pretty much done. That's the whole video. This is I said, it's a gateway to the rest of this series So now that you see that there's a pro and con to folks and to fixed point and to A random implementation you can take this and go implement your own algorithms in engineering with The best possible solution that you could come up with All right, thanks for watching guys. Have a nice day