Review Show
Goal: Learn Higher Order Functions
Review: | Newish: |
---|---|
- bigint/4096_t | - headers |
- extended GCD | - high order functions |
- headers |
- There are no required exercises of this lab.
- It is supplementary material to the BigRSA homework.
- Specifically, it provides helper functions for BigRSA
Podman Show
Setup
- For this lab, I used the following Containerfile
Containerfile
FROM ubuntu
RUN apt update && apt install gcc vim python3 libgmp3-dev -y
- You will note it includes LibGMP.
- Read more
- Watch more
- LibGMP shouldn’t be used in the final product but can be helpful in testing.
- I will make no use of LibGMP but you may wish to do so while working on the lab.
- I will refer to it frequently and it may be worth fiddling around with.
- I worked in an
ops_ui.c
andops_ui.h
file, that I used in BigRSA- It can be helpful to directly add todays work to
4096_t
- or not, up to you.
- It can be helpful to directly add todays work to
Header Show
This is a partial refresh from bigadd
and should be familiar, but contain novel material.
The .h file
- There are two main types of C files.
- The .c files we have been working with.
- The .h files we have incorporated via
#include
ops_ui.h
- Create two new files.
- ops_ui.c, and
- ops_ui.h
- We will work within both.
- You may, perhaps, which to keep both open in separate vim windows, or
- Implement completely in 4096_t.c then split latter.
- We will want to be able to
#include
this work into BigRSA.c next week.
Double Inclusion
- By convention, there is a
double inclusion
guard
ops_ui.h
/* ops_ui.h */
#ifndef _ops_ui_H
#define _ops_ui_H
/* We will put stuff here soon */
#endif /* _ops_u_H */
ops_ui.c
/* ops_ui.c */
/* We will put stuff here soon */
Other headers
- Vs.
4096_t.h
, I implementedops_ui.h
on top of4096_t.h
.- So no system header files - like
stdio
- But included
4096_t.h
. - But that file is in another directory!
- So no system header files - like
- My file system looked something like this:
.
├── 4096_t
│ ├── 4096_t.c
│ ├── 4096_t.h
│ └── biggmp.c
└── ops_ui
├── ops_ui.c └── ops_ui.h
- It actually had way more stuff, but I cut out everything that isn’t relevant.
Relative paths
- 4096_t is in another directory so I can simply write:
#include "4096_t.h"
- Rather, I must give the relative path - how to navigate from
ops_ui.h
to4096_t.h
- If I wanted to navigate through the filesystem, I may do something like the following:
$ pwd /home/user/dev/crypto/ops_ui $ cd .. $ pwd /home/user/dev/crypto $ cd 4096_t $ pwd /home/user/dev/crypto/4096_t $ head -1 4096_t.h /* 4096_t.h */
- Or I may do something much shorter:
$ pwd /home/user/dev/crypto/ops_ui $ head -1 ../4096_t/4096_t.h /* 4096_t.h */
- I can refer to to files the same way from within C:
#include "../4096_t/4096_t.h"
- Note - this will only work if you have a setup with a similar file structure!
Functions
- I noticed when working on BigRSA I often:
- Had a big 4096-bit integer
- That I wanted to add
1
or6
to - Or compare to
0
- This is a common problem, and reolved in our reference implementation (LibGMP) using the
_ui
suffix. - Quoth LibGMP
Function: void mpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2)
Function: void mpz_add_ui (mpz_t rop, const mpz_t op1, unsigned long int op2)
- Both add together a big number named
op1
- That is,
mpz_add
adds it to a big numberop2
- And
mpz_add_ui
adds it to an unsigned long intop2
- That is,
- Both store the sum in the big number
rop
- I recommend implementing each of the following.
- Note that I place the return value last not first
ops_ui.h
uint64_t add_ui(uint64_t *big, uint64_t lil, uint64_t *out);
uint64_t sub_ui(uint64_t *big, uint64_t lil, uint64_t *out);
uint64_t mul_ui(uint64_t *big, uint64_t lil, uint64_t *out);
uint64_t quo_ui(uint64_t *big, uint64_t lil, uint64_t *out);
uint64_t rem_ui(uint64_t *big, uint64_t lil, uint64_t *out);
- Before you start implementing these operations, read the
lambda
heading.
Lambda Show
Higher Order Functions
- Despite my best efforts, there is no graceful way to implement within C functions which return other functions.
- I did not say no way! I said no graceful way.
- Using C++ is not graceful!
- There is, I think, an extraordinarily graceful to implement functions which accept as a parameter/argument some other function(s).
- We simply specify that an argument has some function type.
- We begin with a minimal example.
ctype.h
- One common application for functions is to check if a character is a printing character:
- A number, like
0
ori
? - A letter, like
O
ori
? - A control character, like
\0
or\n
- A digit, like
0
or1
- A space, like
or
\n
- A number, like
ctypes.h
provides functions to test each of these.
/* For some reason this is int -> int *?
int isalnum( int ch );
- Let’s make a table.
- In the leftmost column, we will print each of the first 127 characters
- Then we we will have a column for each of the
ctypes
- We will specify
T
orF
for “True” or “False” membership in the ctype. - So we need a way to go from character-to-character with a bunch of int-to-int functions.
- Here are some functions to use:
isalnum
isalpha
isdigit
islower
isprint
ispunct
isspace isupper
- We can use them as follows:
tedious.c
#include <stdio.h>
#include <ctype.h>
int main() {
char buf[8] = "aA1. _\t";
if (isalnum(buf[0])) {
("T");
printf} else {
("F");
printf}
("\n");
printfreturn 0;
}
- It would be tedious to write a wrapper function for each of these.
- We treat them as a lambda function, a function for which we neither know nor care the name, and know only the type.
- Let’s examine more closely these lines:
if (isalnum(buf[0])) {
("T");
printf} else {
("F");
printf}
- We:
- Take a function name
- Take an array name
- Take an array index
- Apply the function name to index element of the array.
- Print based on the result.
- Let’s write a function.
- It doesn’t return anything, it just prints.
- It takes a function… somehow.
- It takes a character pointer for an array.
- It takes a numberical value for an array index.
(function, array, index) char_to_bool
- This is not well-formed C - let’s add types.
void char_to_bool(function, char *array, int index) # should be size_t, but.
isalnum
also has a type - the typeint -> int
in Python, but in C?
void char_to_bool(int (function)(int), char *array, int index).
- We say `function` is a type that given some `int` returns some `int`
- How do we use it?
- The same way we would any other function for which we know a name or alias!
void char_to_bool(int (function)(int), char *array, int index) { if (function(array[index])) { ("T"); printf} else { ("F"); printf} return; }
- Put it altogether
goated.c
#include <stdio.h>
#include <ctype.h>
void char_to_bool(int (function)(int), char *array, int index) {
if (function(array[index])) {
("T");
printf} else {
("F");
printf}
return;
}
int main() {
char buf[8] = "aA1. _\t";
(isalnum, buf, 0);
char_to_bool("\n");
printfreturn 0;
}
Longer arrays
- Why not examine the char in multiple ways?
- We
goated.c
#include <stdio.h>
#include <ctype.h>
void char_to_bool(int (function)(int), char *array, int index) {
if (function(array[index])) {
("T");
printf} else {
("F");
printf}
return;
}
void char_to_bools(char *array, int index) {
int (*functions[8])(int) = {
,
isalnum,
isalpha,
isdigit,
islower,
isprint,
ispunct,
isspace
isupper}, i;
for (i = 0 ; i < 8 ; i++) {
(functions[i], array, index);
char_to_bool}
return;
}
int main() {
char buf[8] = "aA1. _\t";
(buf, 0);
char_to_bools("\n");
printfreturn 0;
}
- We can see the output:
{.email}} TTFTTFFF
Closing thoughts
- An astute will have noticed that:
- All of the “big” operations have the same function type.
- All of the “_ui” operations have the same function type.
- All of the “_ui” operations can utilize the underlying “big” operation.
- This is not efficient for computing performance, but is efficient from code reuse.
Tester Show
- Unusually for this lab I have provided a tester for the
ops_ui
files. - Separately, I have provided
biggmp.c
- This file uses the GMP library to implement 4096_t.
- It is a “drop in replacement”
- Remove
4096_t.c
from yourgcc
command. - Replace it with
biggmp.c
- Add
-lgmp
flag togcc
- Remove
- Compiling with
4096_t
andbiggmp
should be functionally identical.- They will differ in how they handle overload, but there are notes in
biggmp
on how to fix that at a small performance cost.
- They will differ in how they handle overload, but there are notes in
Autograder
- The interface implemented by the autograder may be informative here.
- It uses a Python script.
- It uses a dedicated .c file with a
main
function. - It differents from the 4096_t grader:
- It uses
gcc ../4096_t/4096_t.c ops_ui.c tester.c
- It can use
gcc ../4096_t/biggmp.c ops_ui.c tester.c -lgmp
- You can change this if you use a different directory structure.
- There is a better way to write these gcc commands that we will cover after midterm.
- It uses
- It uses Python
subprocess
to examine the results.
- I was unable to achieve a bugfree multiply absent this interface, but was able to progress rapidly once I developed it.
BigMax Show
- I wrote two other “big” helper functions.
- Can be completed as part of this lab, part of BigRSA, or not at all.
- They aren’t exactly big x unsigned operations, but could live in the same file.
BigMax
- I needed a way to see if things were bigger than other things.
- My subtraction only worked if the initial argument, the minuend, was larger than the final argument, the subtrahend.
- Additionally, computing extended gcd’s generally involves finding a maximal and minimal value.
- I just returned a
0
or a1
depending on whether the initial argument was the max.
BigMid, mid_ui
- In LaTeX I am accustomed to denoted “\(a\) is divisible by \(b\)” or “\(b\) divides \(a\)” as follows: \[ a \mid b \]
- This uses the LaTeX
\mid
command. - It is the same idea as
a % b == 0
- I wanted to call this
div
but that was already used for division. - I mostly used this for prime generation.