 Welcome back to 105. Thank you for joining me on today's cold evening. So today we get to talk about math and random numbers. So by the end of this lecture, you will definitely have everything you know to complete lab one and to complete a bunch of lab two. So let's get into it. So C comes with the standard C library and it also comes with a math library. So we've seen a little bit of math so far, basic arithmetic, adding, subtracting, multiplying, dividing, getting the remainder sometimes. But if we want to do anything more advanced in arithmetic, we need to use this library. So to add all function prototypes from the library to our code, which is a new word for us today, we need to do like a hashtag include and then math.h on a new line. And that's before creating the main function like we had with our other library includes. So function prototype, new word today. So a function prototype tells you about the inputs and outputs of a function. You might hear the word function declaration, almost the same thing for the purposes of this course. We can consider it the same thing. Don't worry about the difference. So a function prototype tells you the input and output types to the function. So all function prototypes have this form. So the output type comes first. So you would see that this kind of looks like main, main starts with int and that is the output of main. So in general, we can have different output types. We can create functions that output different things. So first thing is the output type, then the function name comes next. In this case, we've only really seen main and then there is a parenthesis and then there are input types here. So you're allowed to have more than one input. We've already seen that with printf. So printf will take more than one input and so we'll scanf. Void is that special type that means nothing. So we can have multiple input types. We just separate them by commas and input types can be void and that just means there are no inputs to this function and that is exactly what we have with main. So some examples of function prototypes are I'll just put, start adding comments to the code so that everything is all together. So if I have something that says double foo and then brackets double and then every line ends with a semicolon that means that I'm declaring that there is a function called foo that takes a single double as input and then outputs a double. So everyone okay with that? Function one input double output double. If I have something that looks like this I have double foo double comma double. Well, that means the function is called foo. It takes two doubles as inputs or there's two double arguments if you wanna say it like that and it outputs a double. Could also have void foo double. So that means there's a function called foo takes a single double as an input has no output. And finally I could have something like this. Again, another function called foo. This time it goes double foo void. That means it has no inputs and then outputs a double. So any questions about those function prototypes? All right, we are good. So this is how you will read what's in the library. Yep. Oh, so yeah, there's a question. So in the last case, do I have to say void or can I just type nothing? So depending on the version of C you use you can type nothing. The strictest sense of C wants you to type void there. So sometimes it's up to you should just get into the habit of just doing whatever C tells us to do. So that's the safest one. Sometimes you can get rid of it. So you might see function prototypes that can actually optionally name the arguments if you want but these names are only for your benefit to make it easier to read. So example, I could have double foo and then double X and then double Y. So those kind of look like variable names but they're just there to help you understand which arguments are which. You might be confused if you see a function that takes like three doubles that does something you might write the order is important, which one is which. So in order for you to understand which is which you can optionally name them and then from the name you know which one to use for what. So the order matters for all of whenever we use functions. So when you actually use this function those names don't matter, right? I don't have to have a variable called X. I don't have to have a variable called Y. They don't have to match whatever is in that function prototype. So just to demonstrate that I could just say when I use this function I could just call it with like you know 7.0 or something like that and if I have something like 7.0 like just an actual number that's a value the compiler calls those literal so it's like a literal number. Yep, yeah so these like having no name whoops like here just foo double double so if you were to write this function right you would have to name them but in this case this is only to say what arguments the function takes that's the only purpose for this but when we get into writing functions yeah we'll have to name them. But we're not writing functions yet that's later in the course. All right, any other questions? Good. All right so here's some background knowledge because all right first off this little symbol here what do you want me to call that? Most people probably your age hashtag is that a thing? Hashtag pound hash any preferences? I don't really care what I call it. Hashtag sure. All right so there's something called a C preprocessor that's part of the compiler that runs before the compiler actually converts what you wrote into machine code so this is not testable so this is just to help you understand what happening I won't, we won't ever ask you a question about it other sections probably don't even go over this so basically how to interpret that as anything that starts with like a hashtag it's technically called a preprocessor directive so that's to tell the preprocessor to do anything do something. So that include preprocessor directive by the time it actually compiles it replaces that include with the contents of that file so there's a file somewhere in this case that would be called like math.h or std.io.h or something like that that would actually be a file on your machine and whenever the compiler runs it will find that file and just replace that hashtag include with the contents of that file so those files you might have noticed so far they've all ended in .h it's because they are called header files don't ask me why we call them header files because they're supposed to be at the top or the head of your program so that's why we call them header files I guess basically all those header files do is define a bunch of function prototypes in them so the library will come with one or more header files that contains all the function prototypes that you can use in that library so we can see what we can use in the math library today so for instance there's a function to actually compute the square root so in math we'd write square root of x we can't just write squiggly lines in C we have to just use things on our keyboard so in C we need to use a function and it's called you'll notice this in computing we like having short forms of stuff so it's not called square root we tried to make it as short as possible so it's called squirt so don't ask me why just to save a few keystrokes I guess and it takes a double so in this case you could call it an x just to match that so it makes sense and then it returns a double so for example if I called squirt with 4.0 well it takes the square root of 4 square root of 4 is 2 so you would get the value 2 back out of it whenever you use it so questions about that alright that's the last thing you finally need for lab 1 part 3 now you can do all of lab 1 so you should be good now so from this point you should be able to complete lab sooner than this we had the start of the course so that's why so here's an example in code if I was using square root and I have all of my includes at the top so I have math.h that's where that squirt is the square root function is then I have standard io for printf then I have standard lib for that exit success value there so I just don't have a magic value if I didn't want to have exit success and just put 0 there I wouldn't need that one but exit success it's part of this header file so in main I could have double y equals 4.0 then I could create a new variable called y square root and then assign it the value I get from that function and then if I go ahead and print it with just one decimal point if I run this I should see what I saw in the previous slide and square root of 4.0 equals 2.0 any questions about that? pretty good so far so here is some of the extra stuff so if we wanted to we could create our own header file so for example one of the things in that math.h header file it's going to contain something that looks exactly like this it's going to contain the function prototype for square root so it's going to be like double square root double x it may or may not have the x there depending on how nice they are and when I use it in my program I could actually just do this if I create a file called square root.h so I create a header file I could instead do include the header file that I created and you might notice here I have double quotes here instead of those angled brackets so it has a slightly different meaning so if you have angled brackets the compiler will search for that file in the standard library places if you just have a double quote there it will search for it in all the standard places and also in the current directory so you could create this and it can actually go ahead and use it if you want so I could have my main exactly the same as before and then before compilation what the preprocessor is going to do is replace that hashtag include so in this case if all my square root.h file contains is this function prototype after that preprocessor runs and it gets rid of all the hashtags to the compiler it will see this as its code so it will see the function prototype for square root and then my main that actually uses it and here is that note if you want it that tells you the difference between the file name being in the angled brackets that's just the compiler to look for the file in the default directories while if it's double quotes looks for the file in the same directory as the code this probably is not testable this is just to help you kind of understand what the compiler is actually doing and trying to get rid of any magic it has that hashtag include it's kind of confusing for a lot of people but really all it's doing those files does have a bunch of function prototypes in them so you don't have to type it out yourself or remember what arguments each function takes they all do it for you so a quick questions about that all right perfect so there are more and more functions so there's a function for exponents so in math I write x to the power of y and in C well of course we need to use a function so there's a function called pow short for power I guess again we just shorten stuff for the hell of it so it takes two doubles an x and a y in that order so that order corresponds to this so your base is x then your exponent is y and for example if I used it so pow two eight is two to the power of eight which should be 256 questions about that all right we're good so there's trigonomic functions as well so we can use sine and sine is defined cosine and it has all those they're defined in radians so in that math dot h file there's also the value of pi in there so to use it you just type M underscore pi so whenever you type M underscore pi the compiler will go ahead and replace that with the actual value of pi and the value they use for pi is 21 digits long which is more precise than a double but unlike numbers not being able to fit when we had integers if you have more digits then can actually be represented by a double it just kind of removes the extra precision tries to be as precise as possible and doesn't have all the weird surprises when we have integers when we had something too big it just turned into a giant negative number that stuff doesn't happen with float so you don't have to worry about it behaves a bit better it tries its best to represent the number so here's an example if I use that so remember pi is like 180 degrees so if I want to get the sine of 90 degrees I just take pi and then divide it by two so that's 90 degrees in radians so sine of 90 degrees or pi divide by two if you're in radians it's just 1.0 so it works and you'll probably need to use this for lab two so there's also logarithmic functions so in math usually we write so we've probably seen like the ln so like the natural log or log to the base e so in C there is a function called log but annoyingly that is not the log so we all know and love the base 10 one they define log as the natural logarithm so to the base e so if I use their log function it corresponds to what we interpret as the natural log or the ln or whatever the hell we call that thing I forget I haven't taken math in a while so if you need the value of e for some reason you can access it the same way you can access the value of pi it's just m underscore e and if I want the actual log so like in math when we write normal logs like normal human beings or log to the base 10 in C it's just called log 10 so that's the common they call it the common logarithm so if you want to use a log base 10 you have to use that one there's also a base two version if you want to use that but C has all the common math things we would need so we can still get a remainder as well using double values so remember we can't use that percent operator that gave us the remainder of an integer division because well those need two integers so if we want to get the remainder using double values we have to use a function so in that case they named it fmod so fmod takes two doubles and it gives you the remainder of x divided by y or the first argument divided by the second argument so it'll give you the remainder as a double so if we did fmod five or sorry 3.5 divided by two our remainder would be 1.5 nothing terribly special here other fun functions we can get the minimum and the maximum of two values this might be useful to you as well so if I have there's fmin so that will take two numbers a and a b order doesn't really matter because it will always give you output the smallest of those two numbers and then there's also an fmax that will always output the larger of the two numbers so if you need to figure out between two numbers which is larger and which is smaller that's the easy way to do it so might not be terribly useful both integers are just literal values so if you ask it you know what's the min of one and two probably a weird thing you should probably just write one because you can figure that out but usually these arguments are going to be variables but just to see what you would get so fmin of like 2.0 and 3.5 well that's two doesn't matter what the order of the arguments are and then same for max if I use the same two numbers in any order the maximum of it would be 3.5 again, any questions? nothing terribly exciting so far, right? all right, that's good if it's boring so far so this is where we get into rounding which gets really kind of weird so there are several different ways to a lot of different ways actually to round floats that all do slightly different things so there is a function called round and all of the rounding will always round to the nearest integer so something .0 and there are different rules for different functions so for example the round function it will always round away from zero if in halfway cases so if I have 1.5 it'll round up to two if I have 2.5 it'll round up to three and the next one our int computes the nearest integer and its rule is like the scientific rounding to try and even out the bias it will always round towards the even number in halfway cases so if I round 1.5 that rounds up to two if I round 2.5 that rounds down to two because that's the nearest even value and I have a little asterisk here that rounding rule is by default we won't tell you how to actually change that so it'll be true but know that there are also a lot of different rounding rules that all do slightly different things which is fairly annoying but these are the only two we have to know for this course in fact I think we just use this one for this course so one that always rounds towards even so here's for example to show the difference so round 1.5 it always rounds away from zero so it will always round up or in this case if it was like a negative 1.5 it would round away from zero to negative two so if I have 2.5 again the round rounds up 3.0 if I do our int so I round to the nearest integer the default rule is to round to the nearest even number so 1.5 rounds to two 2.5 rounds to two any questions about that? alright just kind of something you have to know because well that's how it works just as a note here I think I mentioned it before but I will mention again to be super explicit that using that double format specifier does not change the actual value so if I have a program like this so I create a variable called A and give it the value 2.0 if I do a format specifier where I say hey just don't print anything after the decimal point so I can do 0.0 and then LF for a double if I actually run this that will print 2.0 so it rounded it it obviously used the R int because it rounded to the nearest even number because I didn't get three I got two but this format specifier does not actually change the value of A so even after this print F is done A is still equal to 2.5 so it will only round it for displaying using that format specifier if you actually want to change the actual value to be the random to be the rounded value then we would need to reassign A with the result of like R int or something like that and then for this if I am just printing off one decimal point well in this case it doesn't even need to round and it will just always print 2.5 in this case so any questions about that? So format specifier show you a rounded value but it won't actually change the value itself and you can for this point one you can just use that for the lab you don't have to worry about actually trying to round the value itself at least for lab one so if I need to move if I want to like round more precisely or round a specific decimal point well I need to move the decimal point for actually rounding so if I look at the default rules they're a bit weird if it's not rounding to the nearest integer so if I tell it to just print one decimal point after the zero or sorry if I just tell it to print one decimal point and my number is 2.55 it always just rounds down you have no control over it so if I ran this print F it would print off 2.5 like it just rounded it down it didn't follow any rules or anything like that just rounded down it it should have the rules we had so far it either always rounded up or rounded to the nearest even following any of those rules this point five should actually be like round up the point six right if it followed any logical rules but for anything that is not an integer the print F function specified just rounds down and to show it I can do the same thing with 2.65 and that will print 2.6 it just always rounds down so if I want to actually round that decimal point how we should round numbers I actually need to shift the decimal point before I actually round it so I would have to since all the rules apply just to just to integers if I want to just round to one decimal point I need to move that decimal point one over to the right before I actually round it so in this case I can move that decimal point one over to the right by just multiplying that value by 10 so if I take 2.55 multiply it by 10 then I get 25.5 and then I can round that value so if I round that value and I use it to our what does 25.5 round to 26 right so that does the proper rounding now if I want to get the original value I have I just take that rounded value and then just go ahead and divide it by 10 again so this is what I can do so I can just take 2.65 times it by 10 so then now when I'm doing that R int I'm rounding to the nearest integer and I put the decimal point where exactly where I wanted it to and then after I rounded it I can just restore where the decimal point was originally by just dividing again by the same number so now if I do this it will print 2.6 so it will actually round to the next even number because I'm using R int and then for this one well if I multiply 2.55 times 10 that's 25.5 goes up to 26 move the decimal point over and it would print 2.6 so so the question in the discord is I'll have to check that but those both of those print-ups should round down but if they don't I will check it after the lecture so questions about this so if you want to control the rounding you just have to move the decimal point yourself kind of annoying because all the round functions they only go to the nearest integer alright so there's even more ways to round to the nearest integer if you want to call it rounding so in math has anyone everyone have seen like the ceiling operator before yeah okay so we've seen that so we can't just use those weird characters so in C again it's a function why would we ever call it ceiling we just call it seal um so it can what seal does is it will compute the first integer larger or equal to x and if I want to do the opposite of that so called floor they actually type floor instead of something else stupid so that's good so floor will compute the first nearest integer that is smaller or equal to x so gets a bit fun once we get into negative values you'll have to realize that oh what's larger and what is smaller so the ceiling 1.1 well that goes all the way up to 2 ceiling of 2 it's already an integer so it wouldn't change it would just be 2 ceiling of negative 1.9 well it goes to the next largest number so it wouldn't be negative 2 because negative 2 is smaller than negative 1 so the closest the largest closest integer to this is just negative 1 so be careful if you do this with negative values same deal with floor so if I floor 1.9 that goes all the way down to 0 kind of looks like truncation a little bit if we remember truncation and if I floor 2 well it's already an integer so it stays the same if I floor 1.1 well it goes to the next lowest again so it's either negative 2 or negative 1 in this case it's a floor so negative 2 is smaller than negative 1 so it would be negative 2 questions about that perfect so truncation kind of looked like it's similar to floor and ceiling so when we truncate an integer remember we just chopped off the decimal point and we didn't really care past that so truncate actually happens to be the exact same as floor for positive values and then the exact same as ceiling for negative values so that's what happens when you just chop off the integer so I set it up so the previous slide has all the exact same number so if we truncate 1.1 we get 1 if we truncate 2.0 well stays the same it would be 2 truncate 1.9 so we just chop up chop off the 0.9 negative 1 truncate 1.9 chop it off it's 1 truncate 2 stays 2 again truncate negative 1.1 then we just get negative 1 because it just chops off the anything after the decimal so questions about that perfect so way more math functions available so there's an entire list on Wikipedia that's clickable if you there's a math function you need to find for this course you should only use the functions that just have doubles for all the arguments so we're only considering doubles that's the most precise thing we have just gets rid of a lot of problems if you for some reason if you ever type float realize don't do that because you'll probably get into some very you'll run into some very confusing problems that comes with mixing floats and doubles and weird things might happen so if you need a number that needs a decimal point just always use float and for lab 2 you might find this f abs that is the function to find the absolute value of a float useful for lab 2 so lab 2 you should use that function but just takes a single argument and returns a double just the absolute value all right so we can do a little bit of a problem now so we can make some change using nickels so first actual real problem so right we eliminated the penny so you might get a total that is in dollars and cents but if you need to make change while pennies don't exist anymore you can only actually give back nickels so you have to round to the nearest nickels so we can actually write a program for that so let me switch over real quick so so if we want to problem solve that a lot of actually thinking about the problem is thinking about what inputs you have and what outputs you should get so we're just going to have the user enter an amount in dollars we'll assume it's valid so they'll just use two decimal places and not be mean to us or anything like that so if i want to round to the nearest nickels i should think of what my input is going to be and what my output is going to be so my input is going to be some dollar amount so someone just give me any old dollar amount that we want to round to the nearest nickel 42 dollars and 42 cents so if that is my input then i have to think about what my output would be so if i'm rounding to the nearest nickel what should the result of that be so yeah in this case if it's 42 dollars and 42 cents then my output should be 42 dollars and then 40 cents right so that would be the nearest nickel so what about if i had you know 42 dollars and 43 cents what should my answer be so should it be 42 dollars and 40 cents no i should round up so i should round up so this problem if i'm trying to solve it seems like rounding is my answer so if i want to round to the that amount to the nearest nickel what probably should i do to solve this problem yep multiply it by 20 to get the number of nickels i could do that but that's might be a little hard to read why exactly 20 so 20 nickels in a dollar so i could do something like that but is there any way where i could just get the amount of nickels directly by just dividing by a number i guess it's the same thing so if i want to get the number of nickels i guess the same thing i do but using the nickel amount is i just could take like 42 42 and then divide it by the value of a nickel right so if i just divide it by the value of nickel that will tell me how many nickels i have and in this case it will give me some value like i don't know some number i can't think of right now and then probably like 0.4 right so it will essentially be two out of five nickels so the remainder will be 0.4 if i do the other case where i have this my my decimal point is going to be something 0.6 of a nickel so if i take this and i round it to the nearest integer well this one will round down this one will round up so that gets me to the nearest nickel and then it's like the same thing as as just changing the value so i could just divide it by the value of a nickel get the number of nickels then round that to the nearest integer and then just multiply by the value of a nickel again to actually get the rounded value now so i could do something like print f nearest so i'll print off two decimal places just in case but just to make it look pretty but i could take that amount and then divide it by 0.05 so this is the number of nickels i have and then if i want to get to the nearest nickel i have to round that so my rounding function is going to be our int so that will get me to the nearest number of nickels and then if i want to restore the or get close to the original value again all i have to do is multiply by the number of nickels again or by the value of a nickel again so if i go ahead and compile that and then run it once called nickels so i can try it with the amount that i set aside at the beginning so 0.4204 i argued that it should actually come out to 0.4204 which hey it does so this seems to round to the nearest nickel just to make sure we can test it with another value and let's put a dollar sign there so it looks a bit better so if i had 0.4243 then the nearest nickel is 0.4245 so seems to work so this is the type of code that would be in the cash registers that tell you oh you know how much change they should give you so they'd have to run it to the nearest nickel and then figure out your change based off that by just subtracting it so questions about that usually when you problem solve this generally it's easier just to think of inputs and what the output should be think about how you would get from the input to the output and then after you come up with some solution try it out to make sure that you've done it and we'll get a bunch more practice on this as we go through the course so that was our problem interlude so now we can talk about random numbers to finish this off so there is a c standard library function called rand again why would we call it random or anything like that let's just only use four letters if possible and call it rand that function prototype is in standard lib dot h and the function prototype looks like this it is int rand and then void so it takes no arguments and it gives us an int and that int should be if the name actually means anything it should just be a random integer so it will return a number between zero and rand max in most cases rand max will be that very large number that looks a little bit familiar that is the maximum size of an int which is two to the 32 minus one so if you want to double check that you are free to do that but that's just the maximum value of an int so it will turn a positive value zero all the way up to the maximum positive value of an int so rand it's not actually random it's something called a pseudo random number generator pseudo is just a word for meaning not genuine it's fake it's not actually real so rand uses some mathematical formula to generate the next quote unquote random number it's not actually random it uses a seed value and it creates a deterministic sequence of numbers whenever you call rand deterministic is just another fancy word that we're introduced to in this course that just means it is the exact same every single time so if we want to get a different sequence of random numbers you can change the seed value for rand using while something they cleverly named s rand so the function signature for s rand is void so it gives no output and then it takes an unsigned int seed as a argument and that unsigned is a new thing i think this should be the first time we have seen it so far the type unsigned int that goes back way at the beginning when we talked about whole numbers and what whole numbers we could represent just using amount of bits so if we have unsigned int it means it doesn't have that sign bit so that sign bit isn't there anymore and it can only represent whole numbers so only zero up to a big positive value so if it doesn't have a sign bit and still uses four bytes that means an unsigned bit can represent the numbers zero all the way up to two to the 32 minus one so it can't represent any negative values so it can represent more positive values so in this course we just tell you to always use int even if you know the number can't be negative because generally it is a bad idea whenever you have to mix signed and unsigned and it just causes a lot of problems um like google had a real famous bug with it where they mix them up together and then suddenly i forget what happened i think they probably lost like a billion dollars or something like that so just don't do that for this course we're always going to use int if we don't need a decimal if we need a decimal what type are we going to use a double a double right so double use a decimal if you don't need a decimal use an int if you need to represent something you can type on your keyboard use a char and if you need to represent you know a one or a zero or true and false use a boolean pass that we don't have to use anything else other than those four types yet so what we can do with rand is remember that modulo operator uh so we can actually use that to generate random numbers in any range we want so remember gives us a remainder after doing a integer division and rand while it returns an integer in fact it's always positive so it's a whole number so remember those weird rules when we had mod with negative values where the mod would sometimes be negative sometimes be positive well in this case since rand only returns positive numbers well we don't have to worry about those rules the result of the mod will always be zero or above so if we do something like rand mod 10 the no matter what random number it gives to us the result of modding whatever random number by 10 it's always going to be a number between zero and nine inclusive right so those are the only choices of remainders we have so if we want to generate a random number between one and ten well we can just take rand mod 10 that will give us an always a number between zero and nine so we just take that result and then add one to it so in that case we'll always get a number between one and ten so you can use mod and adding to get any range of random numbers you want so like i said rand mod 10 plus one that means we'll get a random number between one and ten so questions about that cool all right so if we want to generalize this a bit if we want to generate a random number between a and b inclusively where a is less than b we can use this formula so we do rand and then mod b minus a plus one because we want to generate another number and then plus a so we can check that whenever we want to do between one and ten while a was one and then b was ten so that would make sense so ten minus one that's nine plus one so that means we would mod it by ten and then plus a well that was just one so we get the same result so this is that general form of getting a random number between a value so if we want to generate i don't know a random number between one and six what would we do yeah so a would be one b would be six so what would the actual c result be yeah six minus one plus one plus one so at the end we would get rand and then mod six plus one and then that would give us a random number between one and six so any questions at all from today we got a whole four minutes so should be good for lab one courage you to do that or anything else i'll be here for a few minutes if there's any other questions but seems to be good so far so just remember i'm pulling for you we're all in this together