Commit efadd41a authored by Taddeus Kroes's avatar Taddeus Kroes

Merged branches.

parents 1833f32e 316aecce
*.log *.log
*.aux *.aux
*.o
*.pdf
*.swp *.swp
*.swo *.swo
*.toc *.toc
ass*.tar.gz *.gz
compilerbouw/ compilerbouw/
robotica/ robotica/
sum.float
sum.double
sum
speed.*.*
speed
fp
float_double
report.pdf
fd*
pr
floating_point.tex
extra_precision.tex
speed.tex
sum.tex
Makefile.tex
kahan
kahan_sum.tex
CC=gcc
FLAGS=-Wall -Wextra -std=c99 -pedantic -O0 -lm
SPEED_TYPES=float double LD
SUM_TYPES=float double
OPS=ADD DIV MULT SQRT
all: fp speed highlight report.pdf sum kahan pr
highlight: floating_point.tex extra_precision.tex \
speed.tex sum.tex kahan_sum.tex Makefile.tex
s%.tex: s%.c
pygmentize -O style=colorful -o $@ $^
kahan_sum.tex: kahan_sum.c
pygmentize -O style=colorful -o $@ $^
Makefile.tex: Makefile
pygmentize -O style=colorful -o $@ $^
extra_precision.tex: extra_precision.c
pygmentize -O style=colorful -o $@ $^
floating_point.tex: floating_point.c
pygmentize -O style=colorful -o $@ $^
%.pdf: %.tex
pdflatex $^
pdflatex $^
speed: speed.c
for t in $(SPEED_TYPES); do \
for o in $(OPS); do \
sed "s#{TYPE}#$$t#" $^ | sed "s#{OP}#$$o#" > speed.$$t.$$o.c; \
$(CC) $(FLAGS) -o speed.$$t.$$o speed.$$t.$$o.c; \
rm speed.$$t.$$o.c; \
done; \
done;
touch $@
pr: extra_precision.o
$(CC) $(FLAGS) -mfpmath=387 -O2 -o $@ $^
fp: floating_point.o
$(CC) $(FLAGS) -o $@ $^
sum: sum.c
for t in $(SUM_TYPES); do \
sed "s#{TYPE}#$$t#" $^ > sum.$$t.c; \
$(CC) $(FLAGS) -o sum.$$t sum.$$t.c; \
rm sum.$$t.c; \
done;
touch $@
kahan: kahan_sum.o
$(CC) $(FLAGS) -o $@ $^
%.o: %.c
$(CC) $(FLAGS) -o $@ -c $^
%.s: %.c
$(CC) $(FLAGS) -o $* $^
clean:
rm -vf *.o *.i *.s fp pr fd* speed speed.*.* floating_point \
report.pdf *.aux *.log *.toc sum sum.float sum.double kahan
for f in ./speed.[dfL]*; do
echo -n $f' ';
sleep 1;
sudo nice -n -20 time -f %U $f;
done
% Template coming from Pygments (pygmentize with "-O full,preamble")
\usepackage{fancyvrb}
\usepackage{color}
\makeatletter
\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax%
\let\PY@ul=\relax \let\PY@tc=\relax%
\let\PY@bc=\relax \let\PY@ff=\relax}
\def\PY@tok#1{\csname PY@tok@#1\endcsname}
\def\PY@toks#1+{\ifx\relax#1\empty\else%
\PY@tok{#1}\expandafter\PY@toks\fi}
\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{%
\PY@it{\PY@bf{\PY@ff{#1}}}}}}}
\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}}
\def\PY@tok@gd{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
\def\PY@tok@gu{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
\def\PY@tok@gt{\def\PY@tc##1{\textcolor[rgb]{0.00,0.25,0.82}{##1}}}
\def\PY@tok@gs{\let\PY@bf=\textbf}
\def\PY@tok@gr{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
\def\PY@tok@cm{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\def\PY@tok@vg{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.44,0.00}{##1}}}
\def\PY@tok@m{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.38,0.00,0.88}{##1}}}
\def\PY@tok@mh{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.31,0.50}{##1}}}
\def\PY@tok@cs{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.80,0.00,0.00}{##1}}}
\def\PY@tok@ge{\let\PY@it=\textit}
\def\PY@tok@vc{\def\PY@tc##1{\textcolor[rgb]{0.19,0.38,0.56}{##1}}}
\def\PY@tok@il{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.82}{##1}}}
\def\PY@tok@go{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\def\PY@tok@cp{\def\PY@tc##1{\textcolor[rgb]{0.31,0.44,0.56}{##1}}}
\def\PY@tok@gi{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
\def\PY@tok@gh{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\def\PY@tok@ni{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.00}{##1}}}
\def\PY@tok@nl{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.56,0.44,0.00}{##1}}}
\def\PY@tok@nn{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}}
\def\PY@tok@no{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.19,0.38}{##1}}}
\def\PY@tok@na{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.75}{##1}}}
\def\PY@tok@nb{\def\PY@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PY@tok@nc{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.38}{##1}}}
\def\PY@tok@nd{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.31,0.31,0.31}{##1}}}
\def\PY@tok@ne{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.94,0.00,0.00}{##1}}}
\def\PY@tok@nf{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.38,0.69}{##1}}}
\def\PY@tok@si{\def\PY@bc##1{\colorbox[rgb]{0.88,0.88,0.88}{##1}}}
\def\PY@tok@s2{\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@vi{\def\PY@tc##1{\textcolor[rgb]{0.19,0.19,0.69}{##1}}}
\def\PY@tok@nt{\def\PY@tc##1{\textcolor[rgb]{0.00,0.44,0.00}{##1}}}
\def\PY@tok@nv{\def\PY@tc##1{\textcolor[rgb]{0.56,0.38,0.19}{##1}}}
\def\PY@tok@s1{\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@gp{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}}
\def\PY@tok@sh{\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@ow{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.00}{##1}}}
\def\PY@tok@sx{\def\PY@tc##1{\textcolor[rgb]{0.82,0.13,0.00}{##1}}
\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@bp{\def\PY@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PY@tok@c1{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\def\PY@tok@kc{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\def\PY@tok@c{\def\PY@tc##1{\textcolor[rgb]{0.50,0.50,0.50}{##1}}}
\def\PY@tok@mf{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.38,0.00,0.88}{##1}}}
\def\PY@tok@err{\def\PY@tc##1{\textcolor[rgb]{0.94,0.00,0.00}{##1}}
\def\PY@bc##1{\colorbox[rgb]{0.94,0.63,0.63}{##1}}}
\def\PY@tok@kd{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\def\PY@tok@ss{\def\PY@tc##1{\textcolor[rgb]{0.63,0.38,0.00}{##1}}}
\def\PY@tok@sr{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.00}{##1}}
\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,1.00}{##1}}}
\def\PY@tok@mo{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.25,0.00,0.88}{##1}}}
\def\PY@tok@mi{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.82}{##1}}}
\def\PY@tok@kn{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\def\PY@tok@o{\def\PY@tc##1{\textcolor[rgb]{0.19,0.19,0.19}{##1}}}
\def\PY@tok@kr{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\def\PY@tok@s{\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@kp{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.19,0.50}{##1}}}
\def\PY@tok@w{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
\def\PY@tok@kt{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.19,0.19,0.56}{##1}}}
\def\PY@tok@sc{\def\PY@tc##1{\textcolor[rgb]{0.00,0.25,0.82}{##1}}}
\def\PY@tok@sb{\def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@k{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
\def\PY@tok@se{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.38,0.38,0.38}{##1}}
} % \def\PY@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PY@tok@sd{\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.13}{##1}}}
\def\PYZbs{\char`\\}
\def\PYZus{\char`\_}
\def\PYZob{\char`\{}
\def\PYZcb{\char`\}}
\def\PYZca{\char`\^}
% for compatibility with earlier versions
\def\PYZat{@}
\def\PYZlb{[}
\def\PYZrb{]}
\makeatother
#include <stdio.h>
// Calculate 'e' using e=1+1/1!+1/2!+1/3!+1/4!+...
// 8! is 8x7x6x5x4x3x2x1. The series converges rapidly to e.
int fact(int x) { return x > 0 ? x * fact(x-1) : 1; }
int main(void) {
float last_e, e;
int i, max_first = fact(8), max_last = fact(7);
for(e = 1.f, i = 1; i < max_first; i *= i+1 )
e += 1.f / i;
last_e = e;
for(e = 1.f, i = 1; i < max_last; i *= i+1 )
e += 1.f / i;
if( last_e < e + 1.f / (i*8) )
printf("more precision detected!\n");
printf("first: %.80f\nlast : %.80f \n", last_e, e + 1.f / (i*8));
return 0;
}
...@@ -9,5 +9,15 @@ int main(void) { ...@@ -9,5 +9,15 @@ int main(void) {
PRINT_SIZE(double); PRINT_SIZE(double);
PRINT_SIZE(long double); PRINT_SIZE(long double);
float e = 1.f; // Will be replaced in assembly
printf("our epsilon: %.12e\n", e);
printf("f range: [%e, %e]\n", FLT_MIN, FLT_MAX);
printf("d range: [%e, %e]\n", DBL_MIN, DBL_MAX);
printf("ld range: [%Le, %Le]\n", LDBL_MIN, LDBL_MAX);
printf("f epsilon: %e\n", FLT_EPSILON);
printf("d epsilon: %e\n", DBL_EPSILON);
printf("ld epsilon: %Le\n", LDBL_EPSILON);
return 0; return 0;
} }
#include <stdlib.h>
#include <stdio.h>
float kahan_sum(int N) {
float sum = 0.0, c = 0.0, t, y;
for( int i = 1; i <= N; i++ ) {
y = 1.0/i - c;
t = sum + y;
c = (t - sum) - y;
sum = t;
}
return sum;
}
int main(void) {
printf("N = 1e8: %f\n", kahan_sum(1e8));
printf("N = 2e8: %f\n", kahan_sum(2e8));
return 0;
}
\documentclass[10pt,a4paper]{article}
\usepackage{float,url}
% Load code highlighter color scheme
\input{colors}
\title{Modelleren, Simuleren \& Contin\"ue Wiskunde \\
Assignment 1: Floating point arithmetic}
\author{Tadde\"us Kroes (6054129) \and Sander van Veen (6167969)}
\begin{document}
\maketitle
\section{Representation} % {{{
\label{sec:Representation}
We wrote a small C program to determine the properties of floating point numbers
(float, double and long double) on our working machine\footnote{Machine
info...}. To determine the size of the various data types, we used the
\texttt{sizeof} operator. The range of the mentioned data types can derived from
glibc's constants, like \texttt{FLT\_MAX}. Glibc also defines the machine precision
(epsilon) of each data type. \\
\\
The values we found are summarized in the table below:
\begin{table}[H]
\begin{tabular}{l|lll}
Data type & Bytes & Range & Epsilon \\
\hline
\texttt{float} & 4 & $[1.175494 \cdot 10^{38}, 3.402823 \cdot 10^{38}]$
& $1.192093 \cdot 10^{7}$ \\
\texttt{double} & 8 & $[2.225074 \cdot 10^{308}, 1.797693 \cdot 10^{308}]$
& $2.220446 \cdot 10^{16}$ \\
\texttt{long double} & 12 & $[3.362103 \cdot 10^{4932}, 1.189731 \cdot 10^{4932}]$
& $1.084202 \cdot 10^{19}$ \\
\end{tabular}
\caption{Floating point characteristics.}
\end{table}
We will explain the $\epsilon$ we found for the precision of the \texttt{float}
data type. First, we state that epsilon is the smallest representable number
greater than one (thus $a + \epsilon \neq a$, where $|a| \ge 1$). Given the
representation as defined in the lecture slides, we know that the 8-bit exponent
of $1$ is $01111111_2 = 127_{10}$, so $e = 127 - bias = 127 - 127 = 0$. The
mantissa are all zero except for the ``hidden bit'', which is 1. This gives the
exact number $1 \cdot 10^0 = 1.0$. The number closest to one can be made by
making the least significant mantissa `1'. If we apply the given formula, we get
the following decimal value:
$$ (-1)^{sign}(1 + \sum_{i=1}^{23} \ b_{i}2^{-i} )\cdot 2^{(e-127)}
= 1(1 + 1 \cdot 10^{-22}) \cdot 2^0 = 1.000000119209 = 1 + \epsilon $$
We noticed that the precision of numbers between -1 and 1 is much higher, as we
will show later in this report. We thought that the precision would be the same
as the $\epsilon$ which we calculated above, because the exponent is
$00000000_2$ which gives us $e = 0 - bias = -127$. There is no more hidden bit,
but since $2^{-126} = 2 \cdot 2^{-127}$ the precision should be the same. We
think that the higher precision is due to extra precision in the floating point
registers of our computer. Optimization is possible, because numbers between -1
and 1 are ``denormalized'', and therefore contain redundant representations.
% }}}
\section{Calculation speed} % {{{
\label{sec:Calculation speed}
We created one base source file, the executable benchmark files are generated
using the Makefile (which will substitute the variables). The benchmark can be
started using \texttt{./benchmark.bash}.
\begin{table}[H]
\begin{tabular}{l|ll}
Type & Operator & Million ops/sec \\
\hline
\texttt{float} & ADD & 311 \\
\texttt{double} & ADD & 296 \\
\texttt{long double} & ADD & 235 \\
\texttt{float} & DIV & 213 \\
\texttt{double} & DIV & 213 \\
\texttt{long double} & DIV & 190 \\
\texttt{float} & MULT & 9.57 \\
\texttt{double} & MULT & 9.58 \\
\texttt{long double} & MULT & 12.8 \\
\texttt{float} & SQRT & 190 \\
\texttt{double} & SQRT & 222 \\
\texttt{long double} & SQRT & 121 \\
\end{tabular}
\caption{Calculation speed of various mathematical operations.}
\end{table}
\noindent \textbf{Observations}
\begin{itemize}
\item We see that when the data type has a larger storage size, the addition
operation takes increasingly longer.
\item Division and multiplication performance are the same for the data
types \texttt{float} and \texttt{double}. However, division and
multiplication for the \texttt{long double} data type does take longer to
execute.
\item We notice that the square root operation is slower for the
\texttt{float} than for the \texttt{double} data type. Therefore, we think
that the \texttt{sqrt} function of glibc is optimised for the
\texttt{double} data type.
\end{itemize}
% }}}
\section{Summation} % {{{
\label{sec:Summation}
We've calculated $\sum_{i=1}^{N}\frac{1}{i}$ for $N = 10^8$ and $N = 2 \cdot
10^8$ using a forward and backward summation approach, with data types
\texttt{float} and \texttt{double}. The results of this are in the table below.
\begin{table}[H]
\begin{tabular}{l|llll}
Type & N & Forward & Backward & Kahan\\
\hline
\texttt{float} & $10^8$ & $15.403683$ & $18.807919$ & $18.997896$ \\
\texttt{float} & $2 \cdot 10^8$ & $15.403683$ & $18.807919$ & $19.691044$ \\
\texttt{double} & $10^8$ & $18.997896$ & $18.997896$ & \\
\texttt{double} & $2 \cdot 10^8$ & $19.691044$ & $19.691044$ & \\
\end{tabular}
\caption{Results of various summation approaches on floats and doubles.}
\end{table}
\noindent \textbf{Observations}
\begin{itemize}
\item Since the results for the \texttt{double} data type are equal for both
the forward and backward summation approach, we can say that these are the
correct results.
\item For the \texttt{float} data type, we observe that the backward approach
yields a higher result than the forward approach. This can be explained as
follows. When using the forward approach, we start with a small $i$, thus
with a large $1/i$. This means that the initial value of \texttt{sum} is
large. The value will keep growing until the significance of $1/i$ is too
small to add to the result. From this point, no more $1/i$ will be added to
the result because the significance of the individual numbers is too small.
However, the sum of the ignored numbers would be a large enough number to
add to the result. This is why the backward approach yields a higher number:
the sum of the ignored numbers is computed and later the larger numbers
are added. The remaining imprecision is probably due to rounding problems and
the fact that $1/10^8$ and a range of larger numbers are represented as
zeroes in \texttt{float} representation and therefore not added to the
result. This problem does not occur when using the \texttt{double} data type
which has a higher precision, therefore yielding the (correct) higher
result.
\item We can see that both approaches yield the same result for $N = 10^8$
and $N = 2 \cdot 10^8$ when using the \texttt{float} data type. This is due
to the same problem as described above: all numbers in $[\frac{1}{10^8},
\frac{1}{2 \cdot 10^8}]$ are also represented as zero and therefore not added
to the result.
\item To improve the precision of the \texttt{float} data type summation, we
implemented the Kahan summation algorithm. This algorithm basically divides the
summation in a higher- and lower-order part. The lower-order part is used to
compensate for the error at each summation. See
\url{http://en.wikipedia.org/wiki/Kahan_summation_algorithm} for more
information about this algorithm. The results are in the last column as the
table, we can see that the algorithm yields the correct number. We know this
because they are equal to the result of the \texttt{double} summations (but
rounded to the precision of a \texttt{float}, of course).
\end{itemize}
% }}}
\section{Extra precision} % {{{
\label{sec:Extra precision}
Our machine has an Intel Core2 Duo cpu (cpu type is E6750) running at 2.66GHz.
Because Intel added the x87 instruction set (a subset of x86), the FPU
(floating point unit) has a more precise floating point register.
To demonstrate this, we created simple C program, which will approximate the
constant $e$ twice. The first time it will save the final result in a float, the
second time it will store the result in the floating point register. The second
approximation is compared to the first and if the first approximation is large
than the second, the processor has a more precise floating point register. The
simple C program is listed in the appendix \ref{sec:extra_precision.c} and
produces this output:
\begin{verbatim}
$ ./pr
more precision detected!
first: 2.6910297870635986328125000000000000000000000000000000000
last : 2.6910298253667153112189680541632696986198425292968750000
\end{verbatim}
% }}}
\appendix{}
\section{floating\_point.c} % {{{
\label{sec:floating_point.c}
\input{floating_point}
% }}}
\section{speed.c} % {{{
\label{sec:speed.c}
\input{speed}
% }}}
\section{sum.c} % {{{
\label{sec:sum.c}
\input{sum}
% }}}
\section{kahan\_sum.c} % {{{
\label{sec:kahan_sum.c}
\input{kahan_sum}
% }}}
\section{extra\_precision.c} % {{{
\label{sec:extra_precision.c}
\input{extra_precision}
% }}}
\section{Makefile} % {{{
\label{sec:Makefile}
\input{Makefile}
% }}}
\end{document}
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define ADD(a, b) (a += b)
#define DIV(a, b) (a /= b)
#define MULT(a, b) (a *= b)
// Macro expansion is on purpose here to suppress the `unused var b' warning.
#define SQRT(a, b) a = sqrt(a); b = b
#define LD long double
int main(void) {
int i, max = (int) 1e9;
{TYPE} a = 1.60654, b = 3.1285341;
for(i=0; i < max; i++)
{OP}(a, b);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
{TYPE} sum_forward(int N) {
{TYPE} sum = 0;
for( int i = 1; i <= N; i++ )
sum += 1.0 / i;
return sum;
}
{TYPE} sum_backward(int N) {
{TYPE} sum = 0;
for( int i = N; i; i-- )
sum += 1.0 / i;
return sum;
}
int main(void) {
puts("Using type {TYPE}.");
puts("Forward summation:");
printf("N = 1e8: %f\n", sum_forward(1e8));
printf("N = 2e8: %f\n", sum_forward(2e8));
puts("Backward summation:");
printf("N = 1e8: %f\n", sum_backward(1e8));
printf("N = 2e8: %f\n", sum_backward(2e8));
return 0;
}
q1
q2
q3
q4
q5
*.o
CC=clang
CFLAGS=-Wall -Wextra -pedantic -std=c99 -D_GNU_SOURCE
LFLAGS=-lm
all: q1 q2 q3
q1: q1.o
$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
q2: q2.o
$(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) $(LFLAGS) -o $@ -c $^
clean:
for i in `seq 5`; do \
rm -vf q$$i; \
done;
rm -vf *.o
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define H 1e-3
#define TABLE_LINE(func, x) (printf("%-24s%.12f\t%.12f\n", #x, \
slope_right(func, x, H), slope_central(func, x, H)))
typedef double (*func_ptr)(double x);
double slope_right(func_ptr func, double x, double h) {
return (func(x + h) - func(x)) / h;
}
double slope_central(func_ptr func, double x, double h) {
return (func(x + h) - func(x - h)) / (2 * h);
}
int main(void) {
puts("x\t\t\tright\t\tcentral");
TABLE_LINE(&sin, M_PI / 3);
TABLE_LINE(&sin, 100 * M_PI + M_PI / 3);
TABLE_LINE(&sin, 1e12 * M_PI + M_PI / 3);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define EPSILON 1e-11
typedef double (*func_ptr)(double x);
double bisec(func_ptr f, double left, double right, int *steps) {
int i;
double mid;
for( i = 1; fabs(right - left) > 2 * EPSILON; i++ ) {
mid = (right + left) / 2;
if( f(left) * f(mid) < 0 )
right = mid;
else if( f(right) * f(mid) < 0 )
left = mid;
else
break;
}
*steps = i;
return mid;
}
double func(double x) {
return x * sin(x) - 1;
}
int main(void) {
int steps;
printf("zero point: %.20f\n", bisec(&func, 0, 2, &steps));
printf("Steps: %d\n", steps);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define EPSILON 1e-11
typedef double (*func_ptr)(double x);
double bisec(func_ptr f, double left, double right, int *steps) {
int i;
double mid;
for( i = 1; fabs(right - left) > 2 * EPSILON; i++ ) {
mid = (right + left) / 2;
if( f(left) * f(mid) < 0 )
right = mid;
else if( f(right) * f(mid) < 0 )
left = mid;
else
break;
}
*steps = i;
return mid;
}
double func(double x) {
return x * sin(x) - 1;
}
int main(void) {
int steps;
printf("zero point: %.20f\n", bisec(&func, 0, 2, &steps));
printf("Steps: %d\n", steps);
return 0;
}
/* /*
Author: G.D. van Albada Author: G.D. van Albada
Date: August 26, 2009 Date: August 26, 2009
(c) Universiteit van Amsterdam (c) Universiteit van Amsterdam
In this file the data types and some of the functions declared In this file the data types and some of the functions declared
in the file interval.h for the first assignment in the OS course in the file interval.h for the first assignment in the OS course
for 2009 are defined. for 2009 are defined.
*/ */
/* /*
......
/* /*
Author: G.D. van Albada Author: G.D. van Albada
Date: August 26, 2009 Date: August 26, 2009
(c) Universiteit van Amsterdam (c) Universiteit van Amsterdam
In this file the data types and functions exported by the file In this file the data types and functions exported by the file
interval.c for the first assignment in the OS course for 2009 interval.c for the first assignment in the OS course for 2009
are defined. are defined.
*/ */
/* interval is a pointer to a struct used by the functions /* interval is a pointer to a struct used by the functions
......
...@@ -45,11 +45,11 @@ void mem_available(long *empty, long *large, long *n_holes); ...@@ -45,11 +45,11 @@ void mem_available(long *empty, long *large, long *n_holes);
/* mem_available vertelt de gebruiker hoeveel geheugen er nog /* mem_available vertelt de gebruiker hoeveel geheugen er nog
beschikbaar is beschikbaar is
empty: totale hoeveelheid vrije ruimte empty: totale hoeveelheid vrije ruimte
large: omvang van het grootste gat, gecorrigeerd voor large: omvang van het grootste gat, gecorrigeerd voor
administratie administratie
n_holes: het aantal gaten n_holes: het aantal gaten
*/ */
void mem_exit(); void mem_exit();
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
Any feedback is very welcome. Any feedback is very welcome.
http://www.math.keio.ac.jp/matumoto/emt.html http://www.math.keio.ac.jp/matumoto/emt.html
email: matumoto@math.keio.ac.jp email: matumoto@math.keio.ac.jp
*/ */
/* initializes mt[N] with a seed */ /* initializes mt[N] with a seed */
......
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
Any feedback is very welcome. Any feedback is very welcome.
http://www.math.keio.ac.jp/matumoto/emt.html http://www.math.keio.ac.jp/matumoto/emt.html
email: matumoto@math.keio.ac.jp email: matumoto@math.keio.ac.jp
*/ */
#include <stdio.h> #include <stdio.h>
...@@ -73,7 +73,7 @@ void init_genrand(unsigned long s) ...@@ -73,7 +73,7 @@ void init_genrand(unsigned long s)
/* init_key is the array for initializing keys */ /* init_key is the array for initializing keys */
/* key_length is its length */ /* key_length is its length */
void init_by_array(init_key, key_length) void init_by_array(init_key, key_length)
unsigned long init_key[], key_length; unsigned long init_key[], key_length;
{ {
int i, j, k; int i, j, k;
init_genrand(19650218UL); init_genrand(19650218UL);
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
Deze header file bevat de voor de opgave over high-level scheduling en Deze header file bevat de voor de opgave over high-level scheduling en
geheugen-allocatie benodigde definities geheugen-allocatie benodigde definities
Auteur: Dick van Albada Auteur: Dick van Albada
Vakgroep Computersystemen Vakgroep Computersystemen
Kruislaan 403 Kruislaan 403
Datum: 7 september 2003 Datum: 7 september 2003
Versie: 0.3 Versie: 0.3
Student name .... Sander van Veen & Taddeus Kroes Student name .... Sander van Veen & Taddeus Kroes
Student email ... sandervv@gmail.com & taddeuskroes@hotmail.com Student email ... sandervv@gmail.com & taddeuskroes@hotmail.com
Collegekaart .... 6167969 & 6054129 Collegekaart .... 6167969 & 6054129
Date ............ 10.10.2010 Date ............ 10.10.2010
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
De verschillende soorten events: De verschillende soorten events:
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
de io_proc queue of in de ready queue wil aanpassen, kan dat nu. de io_proc queue of in de ready queue wil aanpassen, kan dat nu.
Finish_event - het lopende proces is beeindigd en in de defunct_proc rij Finish_event - het lopende proces is beeindigd en in de defunct_proc rij
geplaatst. Een goede gelegenheid om nieuwe processen toe te laten. geplaatst. Een goede gelegenheid om nieuwe processen toe te laten.
****************************************************************************/ ****************************************************************************/
typedef enum EVENT {NewProcess_event, Time_event, Ready_event, IO_event, typedef enum EVENT {NewProcess_event, Time_event, Ready_event, IO_event,
Finish_event} event_type; Finish_event} event_type;
...@@ -53,7 +53,7 @@ typedef enum EVENT {NewProcess_event, Time_event, Ready_event, IO_event, ...@@ -53,7 +53,7 @@ typedef enum EVENT {NewProcess_event, Time_event, Ready_event, IO_event,
geheugen-array. Door jouw scheduler een maal te veranderen. geheugen-array. Door jouw scheduler een maal te veranderen.
proc_num is het volgnummer van het proces en wordt door de simulator proc_num is het volgnummer van het proces en wordt door de simulator
gevuld. Niet veranderen. gevuld. Niet veranderen.
****************************************************************************/ ****************************************************************************/
typedef struct PCB typedef struct PCB
{ {
...@@ -90,14 +90,14 @@ pcb *new_proc, ...@@ -90,14 +90,14 @@ pcb *new_proc,
/**************************************************************************** /****************************************************************************
De door de practicum-leiding aangeleverde fucties De door de practicum-leiding aangeleverde fucties
*****************************************************************************/ *****************************************************************************/
double sim_time(); double sim_time();
/**************************************************************************** /****************************************************************************
sim_time geeft de gesimuleerde "wall-clock time" terug. Gebruik sim_time geeft de gesimuleerde "wall-clock time" terug. Gebruik
naar het je goeddunkt naar het je goeddunkt
*****************************************************************************/ *****************************************************************************/
extern void set_slice(double slice); extern void set_slice(double slice);
...@@ -111,7 +111,7 @@ extern void set_slice(double slice); ...@@ -111,7 +111,7 @@ extern void set_slice(double slice);
een set_slice(9.9e12) gedaan om te voorkomen dat de simulator daarop kan een set_slice(9.9e12) gedaan om te voorkomen dat de simulator daarop kan
blijven hangen. blijven hangen.
Gebruik voor deze opgave is niet nodig. Gebruik voor deze opgave is niet nodig.
*****************************************************************************/ *****************************************************************************/
long rm_process(pcb **proces); long rm_process(pcb **proces);
...@@ -123,7 +123,7 @@ long rm_process(pcb **proces); ...@@ -123,7 +123,7 @@ long rm_process(pcb **proces);
rm_process ruimt de eventueel door "your_admin" gebruikte ruimte rm_process ruimt de eventueel door "your_admin" gebruikte ruimte
niet op en geeft ook het gereserveerde geheugen niet vrij. Dat niet op en geeft ook het gereserveerde geheugen niet vrij. Dat
moet je bij een "Finish_event" zelf doen. moet je bij een "Finish_event" zelf doen.
****************************************************************************/ ****************************************************************************/
/*************************************************************************** /***************************************************************************
De functie variabele finale wordt door het hoofdprogramma geinitialiseerd De functie variabele finale wordt door het hoofdprogramma geinitialiseerd
...@@ -137,7 +137,7 @@ long rm_process(pcb **proces); ...@@ -137,7 +137,7 @@ long rm_process(pcb **proces);
Een interessante mogelijkheid is b.v. de samenhang tussen de wachttijd op Een interessante mogelijkheid is b.v. de samenhang tussen de wachttijd op
geheugen en de grootte van het aangevraagde geheugen te onderzoeken. geheugen en de grootte van het aangevraagde geheugen te onderzoeken.
Treedt er starvation op, en zo ja, voor welke processen? Treedt er starvation op, en zo ja, voor welke processen?
****************************************************************************/ ****************************************************************************/
typedef void function(); typedef void function();
...@@ -148,13 +148,13 @@ function *finale; ...@@ -148,13 +148,13 @@ function *finale;
queues te vullen. Daarna worden de statistieken weer op nul gezet. queues te vullen. Daarna worden de statistieken weer op nul gezet.
Definieer zelf een functie waar je reset_stats naar laat wijzen Definieer zelf een functie waar je reset_stats naar laat wijzen
om dat ook eventueel voor je eigen statistieken te doen. om dat ook eventueel voor je eigen statistieken te doen.
****************************************************************************e */ ****************************************************************************e */
function *reset_stats; function *reset_stats;
/**************************************************************************** /****************************************************************************
De door de practicanten te schrijven routine De door de practicanten te schrijven routine
****************************************************************************e */ ****************************************************************************e */
void schedule(event_type event); void schedule(event_type event);
......
...@@ -107,7 +107,7 @@ static void gup(FILE * log1, FILE * log2, int pipe_id[2], int myNumber) ...@@ -107,7 +107,7 @@ static void gup(FILE * log1, FILE * log2, int pipe_id[2], int myNumber)
/* /*
* Signal handler for SIGINT, SIGTERM and SIGCHLD. * Signal handler for SIGINT, SIGTERM and SIGCHLD.
*/ */
void void
signal_handler(int signum) signal_handler(int signum)
{ {
char * sig = "TERM"; char * sig = "TERM";
...@@ -141,7 +141,7 @@ signal_handler(int signum) ...@@ -141,7 +141,7 @@ signal_handler(int signum)
/* /*
* Main funtion, initiates the program. * Main funtion, initiates the program.
*/ */
int int
main(void) main(void)
{ {
FILE * log1; FILE * log1;
......
...@@ -28,14 +28,14 @@ int diner_finished = 0; ...@@ -28,14 +28,14 @@ int diner_finished = 0;
/* /*
* Release fork taken by a philosopher. * Release fork taken by a philosopher.
*/ */
static inline void release_fork(diner_stats *stats, int f) { static inline void release_fork(diner_stats *stats, int f) {
if(diner_finished) if(diner_finished)
return; return;
// Unlock left or right fork. // Unlock left or right fork.
stats->locked ^= 1 << (f % 2); stats->locked ^= 1 << (f % 2);
pthread_mutex_unlock(forks+f); pthread_mutex_unlock(forks+f);
} }
/* /*
* Try to claim a fork, but do not wait if the fork cannot be claimed. * Try to claim a fork, but do not wait if the fork cannot be claimed.
...@@ -55,7 +55,7 @@ static inline int try_take_fork(diner_stats *stats, int f) { ...@@ -55,7 +55,7 @@ static inline int try_take_fork(diner_stats *stats, int f) {
/* /*
* Claim a fork, and wait (blocking) if the fork is already taken. * Claim a fork, and wait (blocking) if the fork is already taken.
*/ */
static inline void take_fork(diner_stats *stats, int f) { static inline void take_fork(diner_stats *stats, int f) {
if(diner_finished) if(diner_finished)
return; return;
...@@ -63,13 +63,13 @@ static inline void take_fork(diner_stats *stats, int f) { ...@@ -63,13 +63,13 @@ static inline void take_fork(diner_stats *stats, int f) {
pthread_mutex_lock(forks+f); pthread_mutex_lock(forks+f);
stats->locked |= 1 << (f % 2); stats->locked |= 1 << (f % 2);
stats->forks++; stats->forks++;
} }
#define PHILO_EATING \ #define PHILO_EATING \
if(diner_finished) \ if(diner_finished) \
return 1; \ return 1; \
\ \
stats->meals++; stats->meals++;
static const char *philo_type_names[] = {"left", "right", "optimistic", "shy", static const char *philo_type_names[] = {"left", "right", "optimistic", "shy",
"random"}; "random"};
......
...@@ -93,7 +93,7 @@ int index_error = 0; ...@@ -93,7 +93,7 @@ int index_error = 0;
* characterised by Nblocks (the maximum number of entries in the index) * characterised by Nblocks (the maximum number of entries in the index)
* and KeyLength (the length of the key strings). * and KeyLength (the length of the key strings).
*/ */
in_core * in_core *
index_makeNew(unsigned long Nblocks, unsigned long KeyLength) index_makeNew(unsigned long Nblocks, unsigned long KeyLength)
{ {
unsigned long iRecordLength = sizeof(indexRecord) - sizeof(char[8]) + unsigned long iRecordLength = sizeof(indexRecord) - sizeof(char[8]) +
...@@ -263,7 +263,7 @@ in_core *index_readFromDisk(int fid) ...@@ -263,7 +263,7 @@ in_core *index_readFromDisk(int fid)
* it will return -1. (Zero is a valid index value) It needs as input: The * it will return -1. (Zero is a valid index value) It needs as input: The
* sought key The index record The length of the keys. * sought key The index record The length of the keys.
*/ */
static long static long
key_to_index(indexRecord * rec, const char *key, unsigned long KeyLength) key_to_index(indexRecord * rec, const char *key, unsigned long KeyLength)
{ {
int rv; int rv;
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
#define INDEX_H #define INDEX_H
/* ------------------------------------------------------------------------- /* -------------------------------------------------------------------------
Author: G.D. van Albada Author: G.D. van Albada
University of Amsterdam University of Amsterdam
Faculty of Science Faculty of Science
Informatics Institute Informatics Institute
Copyright (C) Universiteit van Amsterdam Copyright (C) Universiteit van Amsterdam
dick at science.uva.nl dick at science.uva.nl
Version: 0.1 Version: 0.1
Date: December 2001 / January 2002 / November 2004 Date: December 2001 / January 2002 / November 2004
Goal: Part of an assignment on file system structure for the operating Goal: Part of an assignment on file system structure for the operating
systems course. It demonstrates many of the administrative and systems course. It demonstrates many of the administrative and
layering structures that are also used in normal file systems. layering structures that are also used in normal file systems.
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
extern int index_error; extern int index_error;
......
...@@ -69,24 +69,24 @@ ...@@ -69,24 +69,24 @@
* A case in point is the very first record in the file. In order to * A case in point is the very first record in the file. In order to
* allow for the insertion of records with low key values, this record * allow for the insertion of records with low key values, this record
* necessarily must have the minimum key value. Luckily, this is well * necessarily must have the minimum key value. Luckily, this is well
* defined: it is the empty string "". This record will be created and * defined: it is the empty string "". This record will be created and
* marked "reserved" right at the start. * marked "reserved" right at the start.
* *
* When creating the file, every Nth (N = NrecPB - 1) record's key will * When creating the file, every Nth (N = NrecPB - 1) record's key will
* be inserted into the index. * be inserted into the index.
* *
* The index will be a tree where every node has up to four children. * The index will be a tree where every node has up to four children.
* The leaf nodes point to the records. The reason for not using a more * The leaf nodes point to the records. The reason for not using a more
* sophisticated tree structure are that not all keys searched for need * sophisticated tree structure are that not all keys searched for need
* appear in the tree. * appear in the tree.
* *
* So the structure will be: * So the structure will be:
* 1 17 33 49 * 1 17 33 49
* 1 5 9 13 17 .. * 1 5 9 13 17 ..
* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 .... * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ....
* *
* The depth of the tree will be determined by Nblocks * The depth of the tree will be determined by Nblocks
* (D = ceil(log4(Nblocks))) * (D = ceil(log4(Nblocks)))
*/ */
#include <stdio.h> #include <stdio.h>
...@@ -97,37 +97,37 @@ ...@@ -97,37 +97,37 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
/* /*
* Use assert to pinpoint fatal errors - should be removed later * Use assert to pinpoint fatal errors - should be removed later
*/ */
#include <assert.h> #include <assert.h>
#include "isam.h" #include "isam.h"
#include "index.h" #include "index.h"
/* /*
* Compile a static structure to store cache statistics * Compile a static structure to store cache statistics
*/ */
static struct ISAM_CACHE_STATS cstat; static struct ISAM_CACHE_STATS cstat;
/* /*
* Just one flag value describing the state of the file for now * Just one flag value describing the state of the file for now
*/ */
#define ISAM_STATE_UPDATING (1024) #define ISAM_STATE_UPDATING (1024)
/* /*
* Catch any calls to debugRecord, so we don't have any warnings :) * Catch any calls to debugRecord, so we don't have any warnings :)
*/ */
#ifndef DEBUG #ifndef DEBUG
# define debugRecord(alpha, beta, gamma) __placeholder() # define debugRecord(alpha, beta, gamma) __placeholder()
static void __placeholder(void) {return;} static void __placeholder(void) {return;}
#endif #endif
/* /*
* An isam file will start with an information block that is described in * An isam file will start with an information block that is described in
* the following typedef. * the following typedef.
*/ */
typedef struct typedef struct
{ {
unsigned long magic; /* Make sure this is an isam file */ unsigned long magic; /* Make sure this is an isam file */
unsigned long version; /* Allow for later versions */ unsigned long version; /* Allow for later versions */
...@@ -223,7 +223,7 @@ enum isam_error isam_error = ISAM_NO_ERROR; ...@@ -223,7 +223,7 @@ enum isam_error isam_error = ISAM_NO_ERROR;
* makeIsamPtr creates an isamPtr given a file header, fills in some data * makeIsamPtr creates an isamPtr given a file header, fills in some data
* and initialises the cache * and initialises the cache
*/ */
static isamPtr static isamPtr
makeIsamPtr(fileHead * fHead) makeIsamPtr(fileHead * fHead)
{ {
isamPtr ipt = (isamPtr) calloc(1, sizeof(isam)); isamPtr ipt = (isamPtr) calloc(1, sizeof(isam));
...@@ -246,7 +246,7 @@ makeIsamPtr(fileHead * fHead) ...@@ -246,7 +246,7 @@ makeIsamPtr(fileHead * fHead)
return ipt; return ipt;
} }
static void static void
dumpMaxKey(isamPtr f) dumpMaxKey(isamPtr f)
{ {
unsigned int i; unsigned int i;
...@@ -263,7 +263,7 @@ dumpMaxKey(isamPtr f) ...@@ -263,7 +263,7 @@ dumpMaxKey(isamPtr f)
/* /*
* Write the file header to disk (again) * Write the file header to disk (again)
*/ */
static int static int
writeHead(isamPtr f) writeHead(isamPtr f)
{ {
#ifdef DEBUG #ifdef DEBUG
...@@ -294,7 +294,7 @@ writeHead(isamPtr f) ...@@ -294,7 +294,7 @@ writeHead(isamPtr f)
/* /*
* You never can predict what junk you get as a file pointer... * You never can predict what junk you get as a file pointer...
*/ */
static int static int
testPtr(isamPtr f) testPtr(isamPtr f)
{ {
if ((!f) || (f->fHead.magic != isamMagic)) { if ((!f) || (f->fHead.magic != isamMagic)) {
...@@ -309,7 +309,7 @@ testPtr(isamPtr f) ...@@ -309,7 +309,7 @@ testPtr(isamPtr f)
* In the remainder of the code, we should not need to worry about how and * In the remainder of the code, we should not need to worry about how and
* where to write a given block from the cache * where to write a given block from the cache
*/ */
static int static int
write_cache_block(isamPtr isam_ident, int iCache) write_cache_block(isamPtr isam_ident, int iCache)
{ {
unsigned long block_no = isam_ident->blockInCache[iCache]; unsigned long block_no = isam_ident->blockInCache[iCache];
...@@ -346,7 +346,7 @@ write_cache_block(isamPtr isam_ident, int iCache) ...@@ -346,7 +346,7 @@ write_cache_block(isamPtr isam_ident, int iCache)
* in an EOF error anyway); we just zero the cache block (corresponding to * in an EOF error anyway); we just zero the cache block (corresponding to
* an empty record). * an empty record).
*/ */
static int static int
isam_cache_block(isamPtr isam_ident, unsigned long block_no) isam_cache_block(isamPtr isam_ident, unsigned long block_no)
{ {
int iCache; int iCache;
...@@ -446,7 +446,7 @@ isam_cache_block(isamPtr isam_ident, unsigned long block_no) ...@@ -446,7 +446,7 @@ isam_cache_block(isamPtr isam_ident, unsigned long block_no)
* function) We'll use the latter approach - it also has the advantage * function) We'll use the latter approach - it also has the advantage
* that we only need to return a single value. * that we only need to return a single value.
*/ */
static int static int
free_record_in_block(isamPtr isam_ident, int iCache) free_record_in_block(isamPtr isam_ident, int iCache)
{ {
unsigned int iFree; unsigned int iFree;
...@@ -485,7 +485,7 @@ free_record_in_block(isamPtr isam_ident, int iCache) ...@@ -485,7 +485,7 @@ free_record_in_block(isamPtr isam_ident, int iCache)
* Strictly for debugging - print some information about a record * Strictly for debugging - print some information about a record
*/ */
#ifdef DEBUG #ifdef DEBUG
static void static void
debugRecord(isamPtr f, unsigned long n, char *from) debugRecord(isamPtr f, unsigned long n, char *from)
{ {
int ib = n / f->fHead.NrecPB; int ib = n / f->fHead.NrecPB;
...@@ -510,7 +510,7 @@ debugRecord(isamPtr f, unsigned long n, char *from) ...@@ -510,7 +510,7 @@ debugRecord(isamPtr f, unsigned long n, char *from)
* yet. * yet.
*/ */
isamPtr isamPtr
isam_create(const char *name, unsigned long KeyLen, isam_create(const char *name, unsigned long KeyLen,
unsigned long DataLen, unsigned long NrecPB, unsigned long DataLen, unsigned long NrecPB,
unsigned long Nblocks) unsigned long Nblocks)
...@@ -622,7 +622,7 @@ error_open: ...@@ -622,7 +622,7 @@ error_open:
return NULL; return NULL;
} }
isamPtr isamPtr
isam_open(const char *name, int update) isam_open(const char *name, int update)
{ {
struct stat buf; struct stat buf;
...@@ -733,7 +733,7 @@ error_file: ...@@ -733,7 +733,7 @@ error_file:
/* /*
* Close an isam file and release the memory used * Close an isam file and release the memory used
*/ */
int int
isam_close(isamPtr f) isam_close(isamPtr f)
{ {
int i; int i;
...@@ -771,7 +771,7 @@ isam_close(isamPtr f) ...@@ -771,7 +771,7 @@ isam_close(isamPtr f)
* record with that key (if it exists), or the next higher key (if that * record with that key (if it exists), or the next higher key (if that
* exists) * exists)
*/ */
int int
isam_setKey(isamPtr isam_ident, const char *key) isam_setKey(isamPtr isam_ident, const char *key)
{ {
int block_no; int block_no;
...@@ -885,7 +885,7 @@ isam_setKey(isamPtr isam_ident, const char *key) ...@@ -885,7 +885,7 @@ isam_setKey(isamPtr isam_ident, const char *key)
* isam_readNext will read the next valid record (from cur_recno and * isam_readNext will read the next valid record (from cur_recno and
* cur_id), if such a record exists * cur_id), if such a record exists
*/ */
int int
isam_readNext(isamPtr isam_ident, char *key, void *data) isam_readNext(isamPtr isam_ident, char *key, void *data)
{ {
int block_no; int block_no;
...@@ -934,7 +934,7 @@ isam_readNext(isamPtr isam_ident, char *key, void *data) ...@@ -934,7 +934,7 @@ isam_readNext(isamPtr isam_ident, char *key, void *data)
* isam_readPrev will read the current record, if it is valid, and then * isam_readPrev will read the current record, if it is valid, and then
* reposition the file to the preceding valid record (if that exists). * reposition the file to the preceding valid record (if that exists).
*/ */
int int
isam_readPrev(isamPtr isam_ident, char *key, void *data) isam_readPrev(isamPtr isam_ident, char *key, void *data)
{ {
int block_no; int block_no;
...@@ -987,7 +987,7 @@ isam_readPrev(isamPtr isam_ident, char *key, void *data) ...@@ -987,7 +987,7 @@ isam_readPrev(isamPtr isam_ident, char *key, void *data)
* isam_readByKey will attempt to read a record with the requested key * isam_readByKey will attempt to read a record with the requested key
*/ */
int int
isam_readByKey(isamPtr isam_ident, const char *key, void *data) isam_readByKey(isamPtr isam_ident, const char *key, void *data)
{ {
#ifdef OPTIMISED #ifdef OPTIMISED
...@@ -1060,7 +1060,7 @@ isam_readByKey(isamPtr isam_ident, const char *key, void *data) ...@@ -1060,7 +1060,7 @@ isam_readByKey(isamPtr isam_ident, const char *key, void *data)
memcpy(data, data((*isam_ident),iCache,rec_no), isam_ident->fHead.DataLen); memcpy(data, data((*isam_ident),iCache,rec_no), isam_ident->fHead.DataLen);
return 0; return 0;
#else #else
/* /*
* STEP 5: This implementation is inefficient, and I have not verified * STEP 5: This implementation is inefficient, and I have not verified
* that it really works according to its specification For one thing, it * that it really works according to its specification For one thing, it
* does not test for a valid isam_ident before use. It is probably better * does not test for a valid isam_ident before use. It is probably better
...@@ -1111,7 +1111,7 @@ key_error: ...@@ -1111,7 +1111,7 @@ key_error:
* overflow record position (last block in a record, or a free slot in an * overflow record position (last block in a record, or a free slot in an
* overflow block) * overflow block)
*/ */
static int static int
isam_append(isamPtr isam_ident, const char *key, const void *data) isam_append(isamPtr isam_ident, const char *key, const void *data)
{ {
int block_no; int block_no;
...@@ -1332,7 +1332,7 @@ isam_append(isamPtr isam_ident, const char *key, const void *data) ...@@ -1332,7 +1332,7 @@ isam_append(isamPtr isam_ident, const char *key, const void *data)
return writeHead(isam_ident); return writeHead(isam_ident);
} }
int int
isam_writeNew(isamPtr isam_ident, const char *key, const void *data) isam_writeNew(isamPtr isam_ident, const char *key, const void *data)
{ {
int block_no; int block_no;
...@@ -1669,7 +1669,7 @@ int isam_perror(const char *str) ...@@ -1669,7 +1669,7 @@ int isam_perror(const char *str)
* isam_delete will delete a record if - it exists, - is valid - key and * isam_delete will delete a record if - it exists, - is valid - key and
* data match * data match
*/ */
int int
isam_delete(isamPtr isam_ident, const char *key, const void *data) isam_delete(isamPtr isam_ident, const char *key, const void *data)
{ {
unsigned long block_no; unsigned long block_no;
...@@ -1886,7 +1886,7 @@ isam_delete(isamPtr isam_ident, const char *key, const void *data) ...@@ -1886,7 +1886,7 @@ isam_delete(isamPtr isam_ident, const char *key, const void *data)
* implementation, where far fewer records need to be written, is left as * implementation, where far fewer records need to be written, is left as
* an exercise. * an exercise.
*/ */
int int
isam_update(isamPtr isam_ident, const char *key, const void *old_data, isam_update(isamPtr isam_ident, const char *key, const void *old_data,
const void *new_data) const void *new_data)
{ {
...@@ -2003,7 +2003,7 @@ isam_update(isamPtr isam_ident, const char *key, const void *old_data, ...@@ -2003,7 +2003,7 @@ isam_update(isamPtr isam_ident, const char *key, const void *old_data,
* Like strlen, but with a maximum length allowed. There is "strnlen" in * Like strlen, but with a maximum length allowed. There is "strnlen" in
* GNU libc, but it's non-standard, hence we provide our own version. * GNU libc, but it's non-standard, hence we provide our own version.
*/ */
static long static long
my_strnlen(const char *str, int maxLen) my_strnlen(const char *str, int maxLen)
{ {
const char *s = str; const char *s = str;
...@@ -2020,7 +2020,7 @@ my_strnlen(const char *str, int maxLen) ...@@ -2020,7 +2020,7 @@ my_strnlen(const char *str, int maxLen)
* and complete blocks, separately for sequential part and for overflow * and complete blocks, separately for sequential part and for overflow
* part. Also collect statistics on the key length used. * part. Also collect statistics on the key length used.
*/ */
int int
isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS *stats) isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS *stats)
{ {
int iCache; int iCache;
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
#define ISAM_H #define ISAM_H
/* ------------------------------------------------------------------------- /* -------------------------------------------------------------------------
Author: G.D. van Albada Author: G.D. van Albada
University of Amsterdam University of Amsterdam
Faculty of Science Faculty of Science
Informatics Institute Informatics Institute
Copyright (C) Universiteit van Amsterdam Copyright (C) Universiteit van Amsterdam
dick at science.uva.nl dick at science.uva.nl
Version: 0.1 Version: 0.1
Date: December 2001 / January 2002 / November 2004 Date: December 2001 / January 2002 / November 2004
Goal: Part of an assignment on file system structure for the operating Goal: Part of an assignment on file system structure for the operating
systems course. It demonstrates many of the administrative and layering systems course. It demonstrates many of the administrative and layering
structures that are also used in normal file systems. structures that are also used in normal file systems.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
typedef struct ISAM *isamPtr; typedef struct ISAM *isamPtr;
...@@ -23,34 +23,34 @@ struct ISAM_CACHE_STATS; ...@@ -23,34 +23,34 @@ struct ISAM_CACHE_STATS;
/* isam_create will create an isam_file, but only if a file of that name /* isam_create will create an isam_file, but only if a file of that name
does not yet exist. does not yet exist.
The parameters are: The parameters are:
name: name of the file, possibly including directory information name: name of the file, possibly including directory information
key_len: maximum length of the (character string) key. key_len: maximum length of the (character string) key.
data_len: length of the data field data_len: length of the data field
NrecPB: number of records that should be put into one block (including NrecPB: number of records that should be put into one block (including
one overflow record per block). one overflow record per block).
Nblocks: The number of regular data blocks = number of entries in the Nblocks: The number of regular data blocks = number of entries in the
index index
isam_create will return an isamPtr on success, NULL on failure isam_create will return an isamPtr on success, NULL on failure
*/ */
isamPtr isam_create(const char *name, unsigned long key_len, isamPtr isam_create(const char *name, unsigned long key_len,
unsigned long data_len, unsigned long NrecPB, unsigned long Nblocks); unsigned long data_len, unsigned long NrecPB, unsigned long Nblocks);
/* isam_open will open an existing isam file. /* isam_open will open an existing isam file.
The parameters are: The parameters are:
name: name of the file, possibly including directory information name: name of the file, possibly including directory information
update: (not used) when != 0 the file is opened for reading and writing update: (not used) when != 0 the file is opened for reading and writing
(it actually always is). (it actually always is).
isam_open will return an isamPtr on success, NULL on failure isam_open will return an isamPtr on success, NULL on failure
*/ */
isamPtr isam_open(const char *name, int update); isamPtr isam_open(const char *name, int update);
/* isam_close will close a previously opened/created isam_file /* isam_close will close a previously opened/created isam_file
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
isam_close will return 0 on success, -1 on failure. isam_close will return 0 on success, -1 on failure.
*/ */
int isam_close(isamPtr isam_ident); int isam_close(isamPtr isam_ident);
...@@ -60,30 +60,30 @@ int isam_close(isamPtr isam_ident); ...@@ -60,30 +60,30 @@ int isam_close(isamPtr isam_ident);
If no such record exists, the first record with a larger key will If no such record exists, the first record with a larger key will
be returned, if that exists. be returned, if that exists.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a string containing the requested key. key: a string containing the requested key.
isam_setKey will return 0 on success, -1 on failure. isam_setKey will return 0 on success, -1 on failure.
*/ */
int isam_setKey(isamPtr isam_ident, const char *key); int isam_setKey(isamPtr isam_ident, const char *key);
/* isam_readNext will read the next valid record, if that exists. /* isam_readNext will read the next valid record, if that exists.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a character array where the key will be stored. key: a character array where the key will be stored.
data: pointer to the location where the data are to be stored. data: pointer to the location where the data are to be stored.
isam_readNext will return 0 on success, -1 on failure. isam_readNext will return 0 on success, -1 on failure.
*/ */
int isam_readNext(isamPtr isam_ident, char *key, void *data); int isam_readNext(isamPtr isam_ident, char *key, void *data);
/* isam_readPrev will read the current record, if that exists and is valid and /* isam_readPrev will read the current record, if that exists and is valid and
afterwards position the file at the preceding valid record, if that exists. afterwards position the file at the preceding valid record, if that exists.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a character array where the key will be stored. key: a character array where the key will be stored.
data: pointer to the location where the data are to be stored. data: pointer to the location where the data are to be stored.
isam_readPrev will return 0 on success, -1 on failure. isam_readPrev will return 0 on success, -1 on failure.
*/ */
int isam_readPrev(isamPtr isam_ident, char *key, void *data); int isam_readPrev(isamPtr isam_ident, char *key, void *data);
...@@ -91,11 +91,11 @@ int isam_readPrev(isamPtr isam_ident, char *key, void *data); ...@@ -91,11 +91,11 @@ int isam_readPrev(isamPtr isam_ident, char *key, void *data);
like an isam_setKey followed by an isam_readNext plus a check that the like an isam_setKey followed by an isam_readNext plus a check that the
requested key and the retrieved key are the same. requested key and the retrieved key are the same.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a string containing the requested key. key: a string containing the requested key.
data: pointer to the location where the data are to be stored. data: pointer to the location where the data are to be stored.
isam_readByKey will return 0 on success, -1 on failure. isam_readByKey will return 0 on success, -1 on failure.
*/ */
int isam_readByKey(isamPtr isam_ident, const char *key, void *data); int isam_readByKey(isamPtr isam_ident, const char *key, void *data);
...@@ -103,13 +103,13 @@ int isam_readByKey(isamPtr isam_ident, const char *key, void *data); ...@@ -103,13 +103,13 @@ int isam_readByKey(isamPtr isam_ident, const char *key, void *data);
if such a record exists. As a security measure, it will verify that the if such a record exists. As a security measure, it will verify that the
user has the correct original data. user has the correct original data.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a string containing the requested key. key: a string containing the requested key.
old_data: a pointer to a location containing a copy of the data that old_data: a pointer to a location containing a copy of the data that
the record should contain before modification. the record should contain before modification.
new_data: the new data to be stored in the record. new_data: the new data to be stored in the record.
isam_update will return 0 on success, -1 on failure. isam_update will return 0 on success, -1 on failure.
*/ */
int isam_update(isamPtr isam_ident, const char *key, const void *old_data, int isam_update(isamPtr isam_ident, const char *key, const void *old_data,
const void *new_data); const void *new_data);
...@@ -117,32 +117,32 @@ int isam_update(isamPtr isam_ident, const char *key, const void *old_data, ...@@ -117,32 +117,32 @@ int isam_update(isamPtr isam_ident, const char *key, const void *old_data,
/* isam_writeNew will write a new record to the file, but only if the key is /* isam_writeNew will write a new record to the file, but only if the key is
not yet in use. not yet in use.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a string containing the new key. key: a string containing the new key.
data: the data to be stored in the new record. data: the data to be stored in the new record.
isam_writeNew will return 0 on success, -1 on failure. isam_writeNew will return 0 on success, -1 on failure.
*/ */
int isam_writeNew(isamPtr isam_ident, const char *key, const void *data); int isam_writeNew(isamPtr isam_ident, const char *key, const void *data);
/* isam_delete will delete the record with the given key. As a security /* isam_delete will delete the record with the given key. As a security
measure, it will verify that the user has the correct original data. measure, it will verify that the user has the correct original data.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
key: a string containing the key of the record to be deleted. key: a string containing the key of the record to be deleted.
data: a pointer to a location containing a copy of the data that data: a pointer to a location containing a copy of the data that
the record should contain before deletion. the record should contain before deletion.
isam_delete will return 0 on success, -1 on failure. isam_delete will return 0 on success, -1 on failure.
*/ */
int isam_delete(isamPtr isam_ident, const char *key, const void *data); int isam_delete(isamPtr isam_ident, const char *key, const void *data);
/* isam_fileStats will collect statistics about a given ISAM file. /* isam_fileStats will collect statistics about a given ISAM file.
The parameters are: The parameters are:
isam_ident: the isamPtr for the file. isam_ident: the isamPtr for the file.
stats: the structure to fill in with statistics. stats: the structure to fill in with statistics.
isam_fileStats will return 0 on success, -1 on failure. isam_fileStats will return 0 on success, -1 on failure.
*/ */
int isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS* stats); int isam_fileStats(isamPtr isam_ident, struct ISAM_FILE_STATS* stats);
......
...@@ -48,7 +48,7 @@ static int report = 0; ...@@ -48,7 +48,7 @@ static int report = 0;
* Bereken dagnummer met 1/1/1900 == 1 * Bereken dagnummer met 1/1/1900 == 1
* Routine faalt op en na 1/3/2100 * Routine faalt op en na 1/3/2100
*/ */
static long static long
berekenDag(int dag, int maand, int jaar) berekenDag(int dag, int maand, int jaar)
{ {
long dagen; long dagen;
...@@ -91,7 +91,7 @@ berekenDag(int dag, int maand, int jaar) ...@@ -91,7 +91,7 @@ berekenDag(int dag, int maand, int jaar)
/* /*
* Print klant-informatie * Print klant-informatie
*/ */
static void static void
printKlant(FILE * log, char *kop, char *sleutel, klant * Klant) printKlant(FILE * log, char *kop, char *sleutel, klant * Klant)
{ {
if (kop) { if (kop) {
...@@ -107,7 +107,7 @@ printKlant(FILE * log, char *kop, char *sleutel, klant * Klant) ...@@ -107,7 +107,7 @@ printKlant(FILE * log, char *kop, char *sleutel, klant * Klant)
/* /*
* Maak een random klant * Maak een random klant
*/ */
static void static void
maakKlant(klant *nieuweKlant) maakKlant(klant *nieuweKlant)
{ {
int i, dag, maand, jaar; int i, dag, maand, jaar;
...@@ -147,7 +147,7 @@ static int code = 1000; ...@@ -147,7 +147,7 @@ static int code = 1000;
* Maak een random sleutel, dichtbij de postcode in "code". Verhoog code. * Maak een random sleutel, dichtbij de postcode in "code". Verhoog code.
* Sleutel is een postcode plus huisnummer. * Sleutel is een postcode plus huisnummer.
*/ */
static int static int
maakSleutel(char *sleutel) maakSleutel(char *sleutel)
{ {
int huisnummer; int huisnummer;
...@@ -169,7 +169,7 @@ maakSleutel(char *sleutel) ...@@ -169,7 +169,7 @@ maakSleutel(char *sleutel)
/* /*
* Schrijf een nieuw record op een willekeurige plek in het bestand * Schrijf een nieuw record op een willekeurige plek in het bestand
*/ */
static int static int
randomNieuwRecord(isamPtr ip) randomNieuwRecord(isamPtr ip)
{ {
char sleutel[20]; char sleutel[20];
...@@ -201,7 +201,7 @@ randomNieuwRecord(isamPtr ip) ...@@ -201,7 +201,7 @@ randomNieuwRecord(isamPtr ip)
* Lees sequentieel alle records in bepaald sleutelbereik, en pleeg een * Lees sequentieel alle records in bepaald sleutelbereik, en pleeg een
* bewerking * bewerking
*/ */
static int static int
leesBereik(isamPtr ip, char *minSleutel, char *maxSleutel, int datum) leesBereik(isamPtr ip, char *minSleutel, char *maxSleutel, int datum)
{ {
char sleutel[20]; char sleutel[20];
...@@ -265,7 +265,7 @@ leesBereik(isamPtr ip, char *minSleutel, char *maxSleutel, int datum) ...@@ -265,7 +265,7 @@ leesBereik(isamPtr ip, char *minSleutel, char *maxSleutel, int datum)
} }
int int
leesBestaandRecord(isamPtr ip, int sleutelNr) leesBestaandRecord(isamPtr ip, int sleutelNr)
{ {
klant klantRecord; klant klantRecord;
...@@ -283,7 +283,7 @@ leesBestaandRecord(isamPtr ip, int sleutelNr) ...@@ -283,7 +283,7 @@ leesBestaandRecord(isamPtr ip, int sleutelNr)
return rv; return rv;
} }
int int
poetsBestaandRecord(isamPtr ip, int sleutelNr) poetsBestaandRecord(isamPtr ip, int sleutelNr)
{ {
klant klantRecord; klant klantRecord;
...@@ -310,7 +310,7 @@ poetsBestaandRecord(isamPtr ip, int sleutelNr) ...@@ -310,7 +310,7 @@ poetsBestaandRecord(isamPtr ip, int sleutelNr)
return rv; return rv;
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
isamPtr ip; isamPtr ip;
......
...@@ -24,7 +24,7 @@ code - it lacks comments, naming is ad-hoc, etc. ...@@ -24,7 +24,7 @@ code - it lacks comments, naming is ad-hoc, etc.
#include <string.h> #include <string.h>
#include "isam.h" #include "isam.h"
void void
instruct(void) instruct(void)
{ {
char str[256]; char str[256];
...@@ -65,7 +65,7 @@ instruct(void) ...@@ -65,7 +65,7 @@ instruct(void)
printf("\n"); printf("\n");
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int rv, i; int rv, i;
......
*.log
*.toc
*.aux
report.pdf
report-dot2tex*
dot2tex.cache
all:
pdflatex report.tex
...@@ -360,8 +360,9 @@ fill in the names of files you expect to show up in the directory. ...@@ -360,8 +360,9 @@ fill in the names of files you expect to show up in the directory.
In Git, it is not necessary to mention the renaming of files (since Git tracks In Git, it is not necessary to mention the renaming of files (since Git tracks
content, not files). However, it is required to add the renamed file to Git's content, not files). However, it is required to add the renamed file to Git's
index, otherwise the file is marked as ``deleted''. Git provides a command to index, otherwise the file is marked as ``deleted''. Also, Git provides a command to
move (or rename) files and directories: \texttt{git mv foo bar}. move (or rename) files and directories: \texttt{git mv foo bar}. This will save
you one command to type, compared to \texttt{mv foo bar; git add bar}.
% }}} % }}}
...@@ -369,9 +370,10 @@ move (or rename) files and directories: \texttt{git mv foo bar}. ...@@ -369,9 +370,10 @@ move (or rename) files and directories: \texttt{git mv foo bar}.
\label{sub:discarding-changes} \label{sub:discarding-changes}
If you suddenly think your changes are not necessary or not the right solution, If you suddenly think your changes are not necessary or not the right solution,
you can discard those changes in Git using \texttt{git checkout -- baz.txt}. Or you you can discard those changes in Git using \texttt{git checkout -- baz.txt} for
could reset your source tree to the last commit (thus discarding all changes in a single file or directory. Or you could reset your entire source tree to the
all tracked files made since the last commit) using \texttt{git reset --hard HEAD}. last commit (thus discarding all changes in all tracked files made since the
last commit) using \texttt{git reset --hard HEAD}.
% }}} % }}}
...@@ -454,10 +456,10 @@ developers. Git is designed to handle large branches and merging those branches ...@@ -454,10 +456,10 @@ developers. Git is designed to handle large branches and merging those branches
efficiently. Also notice when pulling from a Git repository, Git will efficiently. Also notice when pulling from a Git repository, Git will
automatically merge two branches (your repository and the public repository). automatically merge two branches (your repository and the public repository).
Consider the situation where we need to create a branch. The following commands Imagine the situation where we need to create a branch. The following commands
will create a branch of the master branch, commit some changes in both branches will create a branch of the master branch, commit some changes in both branches
and then merging the two branches. In this after the merge, only master branch and then merge the two branches. In this example after the merge, only the
is available. ``master'' branch is available.
\begin{verbatim} \begin{verbatim}
$ git branch $ git branch
...@@ -559,6 +561,77 @@ Finished one cherry-pick. ...@@ -559,6 +561,77 @@ Finished one cherry-pick.
create mode 100644 def.txt create mode 100644 def.txt
\end{verbatim} \end{verbatim}
You can also pick multiple commits, for example, by using \texttt{git
cherry-pick master\~{}4 master\~{}2} (two tildes). This will apply the changes
introduced by the fifth and third last commits pointed to by master and create 2
new commits with these changes. And it is possible to give a range: \texttt{git
rev-list --reverse master -- README | git cherry-pick -n --stdin}. This will
apply the changes introduced by all commits on the master branch that touched
\texttt{README} to the working tree and index. Notice the \texttt{-n} flag, so
the result can be inspected and made into a single new commit if suitable.
% }}}
\subsection{Hooks in Git} % {{{
\label{sub:hooks-in-git}
All hooks are stored in your \texttt{.git}-directory, and saved as
\texttt{.git/hooks/HOOKNAME}, where \texttt{HOOKNAME} is in
$\{$\texttt{applypatch-msg}, \texttt{commit-msg}, \texttt{post-commit},
\texttt{post-receive}, \texttt{post-update}, \texttt{pre-applypatch},
\texttt{pre-commit}, \texttt{prepare-commit-msg}, \texttt{pre-rebase},
\texttt{update}$\}$. Example hooks (\texttt{*.sample}) can be found in the
hooks-directory in your \texttt{.git}-directory.
I'll demonstrate the use of a \texttt{pre-commit} hook. This hook is invoked by
'git-commit', and can be bypassed with the \texttt{--no-verify} option. It takes
no parameter, and is invoked before obtaining the proposed commit log message
and making a commit. Exiting with non-zero status from this script causes the
'git-commit' to abort. Aborting on a non-zero status enables a developer to run,
for example, a set of test cases before committing to the ``main'' Git server
(if you're working with a team of developers). In this example hook for
pre-commit, I'll check if the file \texttt{conflict.txt} contains the
(sub)string \texttt{abc}.
\begin{verbatim}
$ cat <<EOF > /tmp/uva-git/a/.git/hooks/pre-commit
#!/bin/bash
[ ! -f Makefile ] || make
EOF
$ chmod +x /tmp/uva-git/a/.git/hooks/pre-commit
$ cat <<EOF > /tmp/uva-git/a/Makefile
all:
$(printf '\t')grep abc conflict.txt
EOF
$ git add Makefile && git commit -m "Added example Makefile."
[master 78f6e33] Added example Makefile.
1 files changed, 2 insertions(+), 0 deletions(-)
create mode 100644 Makefile
$ git pull && git push
$ echo "wrong" > conflict.txt
$ git commit -am "Added 'wrong' text to 'conflict.txt'"
grep abc conflict.txt
make: *** [all] Error 1
\end{verbatim}
\noindent The pre-commit hook works as expected (since \texttt{abc} is not found
in conflict.txt due to the commit). Now, I'll demonstrate forcing the commit,
which will bypass the pre-commit hook:
\begin{verbatim}
$ git commit --no-verify -am "Added 'wrong' text to 'conflict' (forced)"
[master 9fc290e] Added 'wrong' text to 'conflict' (forced)
1 files changed, 1 insertions(+), 1 deletions(-)
\end{verbatim}
\noindent Although the used check (\texttt{grep abc conflict.txt}) in the
example Makefile is pretty useless, the example clearly shows the possibilities
of a pre-commit hook. In this example, I also used here strings (\texttt{<<EOF}
and \texttt{EOF}) to show what data is stored in which file. Here strings allows
a user to paste file content to a file without the need to escape all bash-related
built-in commands (since escaping is normally required to prevent bash from
performing shell expansion).
% }}} % }}}
% }}} % }}}
......
FLAGS=-Wall -Wextra -std=c99 -pedantic
all: fp speed
speed: speed.o
gcc $(FLAGS) -o $@ $^
fp: floating_point.o
gcc $(FLAGS) -o $@ $^
%.o: %.c
gcc $(FLAGS) -o $@ -c $^
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i;
for(i=0; i < 1e9; i++);
printf("i = %d\n", i);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment