Loading prj_c_training_1...
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # this GNU-makefile relies on the GCC toolchain # nb: on Windows, the Mingw-w64 package provides the mingw32-make.exe command # ( see https://web.enib.fr/~harrouet/dev_tools/#windows.mingw )
#~~~~ control global settings ~~~~ # make opt=2 --> enable optimisation, then disable debug, but keep symbols # make opt=1 --> enable optimisation, then disable debug # make opt=0 --> disable optimisation, then enable debug opt=0 # make clang=1 --> use clang/clang++, not gcc/g++ # make clang=0 --> use gcc/g++, not clang/clang++ clang=0 # make wasm=1 --> target webassembly rather than the native platform # make wasm=0 --> target the native platform rather than webassembly wasm=0
#~~~~ build library or programs ~~~~ # if LIB_TARGET is provided, this library will be built (with its # platform-specific name), otherwise ${EXE_PREFIX}* programs will be built LIB_TARGET= EXE_PREFIX=prog
#~~~~ detect operating system ~~~~ ifneq (${OS},Windows_NT) ifneq (,${findstring Ubuntu,${shell lsb_release -i 2>/dev/null}}) OS:=Ubuntu else ifneq (,${findstring Raspbian,${shell lsb_release -i 2>/dev/null}}) # Standard distribution for Raspberry-Pi OS:=Raspbian else OS:=${strip ${shell uname -s}} endif ifneq (,${findstring Microsoft,${shell cat /proc/version 2>/dev/null}}) # Windows-Subsystem-for-Linux OS:=${OS}_WSL endif endif
#~~~~ adjust project-specific settings ~~~~ CPPFLAGS= # CPPFLAGS+=-I header/path LDFLAGS=-lm # LDFLAGS+=-L library/path -Wl,-rpath,library/path -l library_name CFLAGS= CXXFLAGS= BINFLAGS= ifneq (,${findstring Windows_NT,${OS}}) # nothing special for now else ifneq (,${strip ${LIB_TARGET}}) BINFLAGS+=-fPIC endif ifneq (,${findstring Darwin,${OS}}) # nothing special for now else ifneq (,${findstring Ubuntu,${OS}}) # sanitizer sometimes requires gold-linker on Ubuntu LDFLAGS+=-fuse-ld=gold else ifneq (,${findstring Raspbian,${OS}}) # some warnings may appear when mixing g++-6 and g++-7 on Raspbian CXXFLAGS+=-Wno-psabi else # nothing special for now endif endif endif
#~~~~ adjust platform-specific features (Posix/Windows/Emscripten...) ~~~~ ifneq (,${findstring Windows_NT,${OS}}) LIB_PREFIX= LIB_SUFFIX=.dll EXE_SUFFIX=.exe SKIP_LINE=echo. REMOVE=del /q else LIB_PREFIX=lib ifneq (,${findstring Darwin,${OS}}) LIB_SUFFIX=.dylib else LIB_SUFFIX=.so endif EXE_SUFFIX= SKIP_LINE=echo REMOVE=rm -rf endif ifeq (${strip ${wasm}},1) LIB_PREFIX:=lib LIB_SUFFIX:=.bc EXE_SUFFIX:=.html endif
#~~~~ deduce file names ~~~~ ifneq (,${strip ${LIB_TARGET}}) LIB_TARGET:=${LIB_PREFIX}${strip ${LIB_TARGET}}${LIB_SUFFIX} MAIN_C_FILES= MAIN_CXX_FILES= else LIB_TARGET:= MAIN_C_FILES=${wildcard ${strip ${EXE_PREFIX}}*.c} MAIN_CXX_FILES=${wildcard ${strip ${EXE_PREFIX}}*.cpp} endif COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard *.c}} COMMON_CXX_FILES=${filter-out ${MAIN_CXX_FILES},${wildcard *.cpp}} # MAIN_OBJECT_FILES=${sort ${patsubst %.c,%.o,${MAIN_C_FILES}} \ ${patsubst %.cpp,%.o,${MAIN_CXX_FILES}}} COMMON_OBJECT_FILES=${sort ${patsubst %.c,%.o,${COMMON_C_FILES}} \ ${patsubst %.cpp,%.o,${COMMON_CXX_FILES}}} OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES} DEPEND_FILES=${patsubst %.o,%.d,${OBJECT_FILES}} EXE_FILES=${sort ${patsubst %.c,%${EXE_SUFFIX},${MAIN_C_FILES}} \ ${patsubst %.cpp,%${EXE_SUFFIX},${MAIN_CXX_FILES}}} # GENERATED_FILES=${DEPEND_FILES} ${OBJECT_FILES} ${LIB_TARGET} ${EXE_FILES} ifneq (,${findstring Darwin,${OS}}) GENERATED_FILES+=${wildcard *.dSYM} endif ifeq (${strip ${wasm}},1) GENERATED_FILES+=${patsubst %.html,%.js,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.html.mem,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wasm,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wast,${EXE_FILES}} endif GENERATED_FILES+=${wildcard output_* *~}
#~~~~ compiler/linker settings ~~~~ CPPFLAGS+=-MMD -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion CPPFLAGS+=-Wno-unused -Wno-unused-parameter CPPFLAGS+=-Werror -Wfatal-errors CFLAGS+=-std=c99 -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla CXXFLAGS+=-std=c++17 -Wno-missing-braces LDFLAGS+= BINFLAGS+= ifeq (${strip ${wasm}},1) CC=emcc CXX=em++ CPPFLAGS+=-Wno-dollar-in-identifier-extension LDFLAGS+=-s ALLOW_MEMORY_GROWTH=1 else ifeq (${strip ${clang}},1) CC=clang CXX=clang++ else CC=gcc CXX=g++ endif # ifneq (,${strip ${MAIN_CXX_FILES} ${COMMON_CXX_FILES}}) # force c++ link if there is at least one c++ source file LD:=${CXX} else LD:=${CC} endif
#~~~~ debug/optimisation settings ~~~~ ifneq (${strip ${opt}},0) CPPFLAGS+=-DNDEBUG BINFLAGS+=-O3 -ffast-math # BINFLAGS+=-fopt-info-vec-optimized ifneq (${strip ${wasm}},1) BINFLAGS+=-march=native endif ifeq (${strip ${opt}},2) # optimise but keep symbols for profiling BINFLAGS+=-g -fno-omit-frame-pointer else BINFLAGS+=-fomit-frame-pointer endif else CPPFLAGS+=-UNDEBUG BINFLAGS+=-g -O0 ifeq (${strip ${wasm}},1) # sanitizer is not available yet with Emscripten else ifneq (,${findstring Windows_NT,${OS}}) # sanitizer is not available yet on Windows else BINFLAGS+=-fsanitize=address,undefined ifneq (,${findstring Raspbian,${OS}}) # dynamic sanitizer libraries may not be found on Raspbian BINFLAGS+=-static-libasan -static-libubsan endif endif endif
#~~~~ main target ~~~~ all : ${EXE_FILES} ${LIB_TARGET}
rebuild : clean all
.SUFFIXES: .SECONDARY: .PHONY: all clean rebuild
#~~~~ linker command to produce the library (if any) ~~~~ ${LIB_TARGET} : ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -shared -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ linker command to produce the executable files (if any) ~~~~ %${EXE_SUFFIX} : %.o ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ compiler command for every source file ~~~~ %.o : %.c @echo ==== compiling [opt=${opt}] $< ==== ${CC} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CFLAGS} @${SKIP_LINE}
%.o : %.cpp @echo ==== compiling [opt=${opt}] $< ==== ${CXX} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CXXFLAGS} @${SKIP_LINE}
-include ${DEPEND_FILES}
#~~~~ remove generated files ~~~~ clean : @echo ==== cleaning ==== ${REMOVE} ${GENERATED_FILES} @${SKIP_LINE}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<stdbool.h>. Lorsque le compilateur est rigoureux, la conversion d'un réel en entier doit être explicite (cast) afin d'assumer la perte éventuelle de la partie décimale. La construction
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter. Le résultat d'une comparaison est fondamentalement un booléen ; il est inutile de le comparer à un autre booléen pour décider de renvoyer vrai ou faux à l'identique. Une boucle avec compteur se réalise de préférence avec la construction
for(){}.
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter.
for(){}.
for(){}.
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter.
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter.
for(){}.
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter.
for(){}.
for(){}est en général le choix par défaut pour réaliser une boucle, ce problème particulier peut tirer avantage de la construction
do{}while()qui contrôle la condition de continuation après la première itération du corps de la boucle. Une boucle avec compteur se réalise de préférence avec la construction
for(){}. La construction
if(){}/
else{}permet de choisir les instructions que l'on souhaites exécuter.
{1}sont-elles suivies ?
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "computation.h"
#include <stdio.h> #include <math.h>
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void test_is_int(void) { printf("\n~~~~ test_is_int() ~~~~\n"); for(int i=-20; i<=20; ++i) { const double v=i*0.25; if(is_int(v)) { printf("%g is an integer\n", v); } } }
void test_int_abs(void) { printf("\n~~~~ test_int_abs() ~~~~\n"); for(int i=-2; i<=2; ++i) { const int a=int_abs(i); printf("%d ~~> %d ", i , a); if(a==(int)fabs((double)i)) { printf("correct\n"); } else { printf("!!! INCORRECT !!!\n"); } } }
void test_int_square_root(void) { printf("\n~~~~ test_square_root() ~~~~\n"); for(int i=0; i<10000; i=2*i+3) { const int r=int_square_root(i); printf("%d ~~> %d ", i, r); if(r==(int)sqrt(i)) { printf("correct\n"); } else { printf("!!! INCORRECT !!!\n"); } } }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void test_unit_to_percent(void) { printf("\n~~~~ test_unit_to_percent() ~~~~\n"); for(int i=-4; i<=14; i+=2) { const double unit=i*0.1; const int percent=unit_to_percent(unit); printf("%g ~~> %d\n", unit, percent); } }
void test_int_round(void) { printf("\n~~~~ test_int_round() ~~~~\n"); for(int i=-6; i<=6; ++i) { const double v=i*0.2; const int f=int_round(v); printf("%g ~~> %d ", v , f); if(f==(int)round(v)) { printf("correct\n"); } else { printf("!!! INCORRECT !!!\n"); } } }
void test_number_of_digits(void) { printf("\n~~~~ test_number_of_digits() ~~~~\n"); for(int i=0; i<10000; i=2*i+1) { const int n=number_of_digits(i); printf("%d ~~> %d ", i, n); #if 0 // one possible solution if(((i==0)&&(n==1))|| (n==1+(int)log10(i))) #else // a more concise solution const int expected=(i==0) ? 1 : 1+(int)log10(i); if(n==expected) #endif { printf("correct\n"); } else { printf("!!! INCORRECT !!!\n"); } } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main(void) { printf("~~~~ entering main() ~~~~\n"); dummy_function();
test_is_int(); test_int_abs(); test_int_square_root();
test_unit_to_percent(); test_int_round(); test_number_of_digits();
printf("~~~~ leaving main() ~~~~\n"); return 0; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifndef COMPUTATION_H #define COMPUTATION_H
#include <stdbool.h>
void dummy_function(void);
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool is_int(double value);
int int_abs(int value);
int int_square_root(int value);
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int unit_to_percent(double unit);
int int_round(double value);
int number_of_digits(int value);
#endif // COMPUTATION_H
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "computation.h"
#include <stdio.h> #include <math.h>
void dummy_function(void) { printf("in dummy_function()\n"); }
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool is_int(double value) { #if 0 // one possible solution if(value==(int)value) { return true; } return false; #else // a more concise solution return value==(int)value; #endif }
int int_abs(int value) { #if 0 // one possible solution if(value<0) { return -value; } return value; #else // a more concise solution return value<0 ? -value : value; #endif }
int int_square_root(int value) { int square_root=0; for(int i=0; i*i<=value; ++i) { square_root=i; } return square_root; }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int unit_to_percent(double unit) { #if 0 // one possible solution if(unit<0.0) { return 0; } if(unit>1.0) { return 100; } return (int)(unit*100.0); #else // a more concise solution return unit<0.0 ? 0 : unit>1.0 ? 100 : (int)(unit*100.0); #endif }
int int_round(double value) { const int i_value=(int)value; const double delta=value-i_value; #if 0 // one possible solution if(delta>=0.5) { return i_value+1; } if(delta<=-0.5) { return i_value-1; } return i_value; #else // a more concise solution return delta>=0.5 ? i_value+1 : delta<=-0.5 ? i_value-1 : i_value; #endif }
int number_of_digits(int value) { #if 0 // one possible solution int digits=1; for(value/=10; value!=0; value/=10) { digits+=1; } #else // a more concise solution int digits=0; do { value/=10; digits+=1; } while(value!=0); #endif return digits; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~