01/11/09

Un peu de mathématiques d'amateur qui ne se prend pas au sérieux...

Un illustre collègue adepte de l'adjectif "outrant" et moi-même avons décidé que la somme d'un entier et de son carré serait un nombre "outrant", ce qu"on peut presque-formaliser:

n + n^2 , où n est un entier positif


Qu'on peut exprimer comme le produit de deux entier consécutifs:

n(n + 1)

Les premiers nombres outrants sont 0, 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156, 182, 210, 240, 272, 306, 342, 380, 420, 462, 506, 552, 600, 650...

On appelle "puissance outrante" le nombre outrant de base n, 5 à la puissance outrante vaut 30. On note la puissance outrante par un exposant O (la lettre, pas le chiffre), comme dans 11^O = 132.

En fait en cherchant un peu, ces braves petiots n'ont aucune propriété amusante, si ce n'est que 42 en fait partie (puisque c'est 6 à la puissance outrante), ce qui est un fait qui a été accueilli avec beaucoup de joie puisque l'outrant compagnon de mathématiques du dimanche est presque aussi fan de l'humour d'H2G2 que moi-même. 42 est un nombre outrant, et ça c'est vraiment outrant!

L'avantage est aussi qu'un nombre outrant n'est pas fonction des précédents, ce qui facilite la tâche quand pour l'une ou l'autre outrante raison on a besoin de nombres outrants quelconques éventuellement très grands. De la même manière, si on veut obtenir le plus petit nombre outrant qui soit supérieur à un nombre donné, il suffit d'élever sa racine à la puissance outrante. Pratique.

Allez, plus sérieusement, le produit de deux entiers consécutifs a été déjà baptisé et ausculté. On appelle ces nombres les "nombres oblongs", "nombres proniques", ou encore "nombre hétéroméciques". Pourquoi oblong? Parce qu'exprimés figurativement ça donne quelque chose comme ceci:


**

***
***

****
****
****

*****
*****
*****
*****


Un certain John Conway en a parlé en long et en large, d'ailleurs. Oui, le même John Conway que le jeu de la vie.

Je sais, ça ne sert à rien, c'est d'ailleurs pour ça que c'est indispensable.

...la suite par ici...

29/08/09

Deux ans de statistiques LastFM

Ah tiens, ça fait deux ans aujourd'hui. Deux ans que je suis inscrit à LastFM et que son brave petit scrobbler collecte avec patience et méthode mes habitudes musicales. Enfin presque, il manquait jusqu'il y a peu tout ce que j'écoute sur mon iPod, puisque le scrobbling d'iPod n'était pas exactement au point.

Bref...

Pour ceux qui ne connaissent pas encore LastFM, le principe est plutôt simple. Les utilisateurs laissent un logiciel/plug-in collecter des données statistiques sur les morceaux de musique qu'ils écoutent et envoient tout ça sur le site pour se constituer un profil de mélomane. Sur base de ce profil et de folksonomie, le système établit des corrélations de style entre différents artistes; au final ça lui permêt de conseiller à l'utilisateur des découvertes musicales qui devraient lui plaire (et croyez-moi c'est la partie impressionnante, ils se trompent rarement) et lui présenter d'autres utilisateurs aux goûts similaires.

Evidemment, plus on écoute, plus les statistiques sont parlantes, et plus les déductions sont fiables. Avant 500 titres écoutés le système n'essaie même pas de proposer quoi que ce soit, d'ailleurs. Par contre quand on dépasse les 10000 titres il devient d'un précision presque effrayante.

Je me suis inscrit à LastFM le 28 août 2007. Depuis cette date j'ai écouté 37058 titres de 1196 artistes différents et s'il fallait résumer mes goûts à quelques étiquettes elles seraient "industrial, electronic, rock, metal et ebm", amusant pour quelqu'un qu'on appelle "le métalleux" quand même ;). Pas si simplement métalleux que ça finalement, l'homme en noir.

D'ailleurs quand on classe les artistes par nombre d'écoutes ça devient encore plus amusant. En partant du plus écouté ça donne:

  1. Amon Tobin - 819 écoutes

  2. Nine Inch Nails - 808 écoutes

  3. Metallica - 736 écoutes

  4. Combichrist - 547 écoutes

  5. The Chemical Brothers - 544 écoutes

  6. Johnny Cash - 529 écoutes

  7. Suzanne Vega - 510 écoutes

  8. Punish Yourself - 483 écoutes

  9. Caliban - 464 écoutes

  10. System of a Down - 432 écoutes

  11. Lofofora - 412 écoutes

  12. Converge - 382 écoutes

  13. Heaven Shall Burn - 378 écoutes

  14. Tori Amos - 365 écoutes

  15. 65daysofstatic - 354 écoutes

  16. Walls of Jericho - 344 écoutes

  17. Slipknot - 316 écoutes

  18. Baroness - 297 écoutes

  19. Alchemik Babylon Beats - 285 écoutes

  20. The Cinematic Orchestra - 284 écoutes

  21. Ultra Vomit - 269 écoutes

  22. Depeche Mode - 267 écoutes

  23. As I Lay Dying - 264 écoutes

  24. The Faint - 257 écoutes

  25. VNV Nation - 255 écoutes

  26. Creedence Clearwater Revival - 245 écoutes

  27. Cat Power - 243 écoutes

  28. The Cure - 242 écoutes

  29. Tom Waits - 230 écoutes

  30. Aerosmith - 224 écoutes

  31. IAMX - 214 écoutes

  32. Autechre - 211 écoutes

  33. Korn - 210 écoutes

  34. Tamtrum - 207 écoutes

  35. The Dillinger Escape Plan - 202 écoutes

  36. Peter Pan Speedrock - 201 écoutes



Soyons arbitraires et disons qu'au-délà ce n'est plus forcément représentatit, mais on y croise entre autres Renan Luce, Kings of Convenience, Motörhead, Spiritual Beggars, Björk, Nick Cave, Portishead, Leonard Cohen, Crass, Oi Polloi, Jeff Buckley, P!nk, Neil Young, Birdy Nam Nam, Popa Chubby, Mark Knopfler, Einstürzende Neubauten, Elle Fitzgerald, Zenzile et Anthrax ... j'ose m'autoriser à dire que j'ai des goûts variés ;)

Allez, je ferai un état des lieux dans un an alors. En attendant les très curieux peuvent aller par ici.

Music!


...la suite par ici...

24/08/09

Réparation d'un jack de guitare

J'avais il y a quelques temps racheté du matériel (ampli, V-Amp, câbles) à un ami généreux qui préférait confier tout ça à mes mains débutantes plutôt que de le laisser prendre la poussière. Remy, si tu me lis, grand merci à toi ;-) Mais bon, dans le tout il y avait un câble jack qui souffrait de quelques petits faux contacts qui étaient assez désagréables (si vous n'avez pas encore entendu le son d'un contact qui se refait, amplifié... ça vaut le détour). Donc une intervention était de mise.



C'est le genre d'intervention qui peut faire peur quand on ne sait pas par où chercher, et qui est souvent facturé scandaleusement cher en magasin de musique. En fait le cas extrêmement fréquent c'est qu'à forcé de manipuler le câble sans délicatesse le fil s'arrache du jack. Vérification faite, d'un côté tout va pour le mieux dans le meilleur des mondes:


... mais de l'autre les soupçons sont confirmés (et le petit isolant supplémentaire me laisse supposer qu'il n'en est pas à sa première réparation):


Allons-y alors, d'abord dénuder un peu du câble, pour pouvoir dénuder un peu du fil allant à la pointe et ainsi en avoir assez à nu pour le ressouder:


Ce faisant je remarque que l'isolant a cassé, un point de colle salvateur remettra le morceau tombé (qu'on voit à l'arrière-plan près de la pince):


Paré à retirer l'ancienne soudure (oui madame, à la pompe, oui je suis un bourrin):


C'est-y-pas propre ça madame?


Le fil entré dans son petit trou, prêt à être ressoudé:


... et soudé:


On referme le tout, oui il y a un sens bande de brutes:


Et voilà, ready to rock!


L'opération aura duré quelque chose comme un quart d'heure sans se presser. Et avec ça j'ai cinq mètres de liberté au lieu de deux. Ça valait la peine donc ;-)

...la suite par ici...

03/07/09

Project Euler: solution au problème 24, en Python

On commence les deux mois d'été par le suivant des problèmes eulériens, à savoir le Problème 24. Sachant ce qu'est une permutation, on précise qu'on veut obtenir les permutations d'une suite de nombres dans l'ordre lexicographique (ce qui revient à la relation d'ordre du plus petit au plus grand), et on demande quelle est la 1000000ème permutation de la liste 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

L'algorithme est plutôt évident, et j'utilise ici le copain yield qui me permet d'avoir un générateur itérable plutôt de devoir générer toutes les permutations avant d'en prendre la millionnième.


#! /usr/bin/python

# 2009/07/03 - euler024.py
# Solution au Probleme 24 de Project Euler
# http://projecteuler.net/index.php?section=problems&id=24
# Jean Karim Bockstael - jkb@jkbockstael.be


def permutations_gen(string):
if (len(string) == 1):
yield string
else:
for i in range(len(string)):
for subperm in permutations_gen(string[:i] + string[i+1:]):
yield string[i] + subperm

def euler24(string, num):
cnt = 0
for perm in permutations_gen(string):
cnt += 1
if cnt == num:
return perm

print euler24("0123456789", 1000000)



...la suite par ici...

26/06/09

Project Euler: solution au problème 28, en Python

Ça faisait longtemps que je n'avais pas gratifié mon blog d'un des si particulièrement passionnants problèmes de Project Euler. Il était grand temps d'y remédier, donc voici une solution au problème 28.

L'idée est de remplir une grille carrée de nombres, de dimension impaire, qui est remplie des entiers successifs en spirale partant du centre et allant vers la droite et le bas. Aga? En gros, ayant ce genre de chose:


21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13


La somme des éléments de deux diagonales de ce carré de dimension 5 vaut 101. Que vaut la somme pour un carré de dimension 1001?

Je vous avais présenté mon pote Récursion?

#! / usr/bin/python

# 2009/06/26 - euler028.py
# Solution au Probleme 28 de Project Euler
# http://projecteuler.net/index.php?section=problems&id=28
# Jean Karim Bockstael - jkb@jkbockstael.be

def sum_of_diagonals(dimension):
if (dimension == 1):
return 1
else:
corner_tr = dimension ** 2
corner_tl = corner_tr - dimension + 1
corner_bl = corner_tl - dimension + 1
corner_br = corner_bl - dimension + 1
corner_sum = corner_tr + corner_tl + corner_bl + corner_br
return corner_sum + sum_of_diagonals(dimension - 2)

print sum_of_diagonals(1001)


...la suite par ici...

24/06/09

Codechef: Petit déjeuner de l'autre côté du miroir

The Codechef, le concours de programmation organisé par Directi, propose depuis peu deux problèmes par jour via Twitter. Ce matin, le problème est de compter le nombre d'entiers inférieurs à 1000 qui, quand on les ajoute à leur image miroir, forment un entier qui n'est composé que de chiffres impairs.

Exemple simple:

...
20 + 02 = 22 NON
21 + 12 = 33 OUI
22 + 22 = 44 NON
...


Et comme d'habitude, j'ai sorti l'ami Python, celui qui nous veut du bien.


#! /usr/bin/python
# Codechef Twitter Daily 2009/06/24
# How many numbers below 1000 which when added with their respective mirror images result in a number with entirely odd digits?
# 2009/06/24 - Jean Karim Bockstael - jkb@jkbockstael.be


def reverse_number(num):
return int(str(num)[::-1])

def is_all_odds(num):
for digit in str(num):
if (int(digit) % 2 == 0):
return False
return True

def count_mirrors(max):
n_mirrors = 0
for num in range(1, max):
if is_all_odds(num + reverse_number(num)):
n_mirrors += 1
return n_mirrors

print count_mirrors(1000)



...la suite par ici...

16/06/09

Tiens j'avais oublié ça...

Il est un fait établi qu'il m'arrive souvent de perdre de vue quelque chose tant mes occupations et projets sont nombreux et variés. Il est également un fait établi qu'il m'arrive dans ma distraction d'effectuer du nettoyage par le vide et de le regretter après, bien que ça ne porte pas à conséquences (sinon il y aurait une copie de sauvegarde, c'est évident).

Ainsi, dans mon tout premier post sur le présent blog, je donnais un petit teaser d'un projet personnel qui approchait de la fin et que je m'apprêtais à vous dévoiler. J'avais juste montré ceci:

Teaser



Et, comme un distrait que je suis, non content d'avoir oublié de donner suite à cette promesse je me suis permis d'éradiquer par un bon vieux rm des familles le répertoire où je conservais les photos des différentes étapes de la réalisation dudit projet, qui s'étalait sur quelques mois de temps libre trop sporadique.

Bon tant pis, vous n'aurez droit qu'au produit fini alors:



...la suite par ici...

28/05/09

Mastermind, a little more refined...

J'avais posté ici un petit jeu de Mastermind, un furieux premier jet né d'un film trop peu intéressant à la TV et d'une envie de coder "quelque chose". D'une manière ou d'une autre ça valait la peine de faire quelque chose d'un peu plus peaufiné un jour.

Voici qui est un peu mieux. Toujours une interface textuelle sans fioritures, mais le jeu est paramétrable (voir le menu options) et offre le mode de jeu classique et le mode de jeu facile qu'implémentait ma version "quick and dirty".

Au niveau du code c'est du plus propre sans pour autant être de l'objet-pour-faire-de-l'objet. Hack away, have fun!

Ah oui, pour que ce soit un peu plus lisible il n'y a pas de contrôle aux entrées clavier. Si on tape n'importe quoi ça plante de façon insultante, soyez prévenu :)


#! /usr/bin/env python

# Game of Mastermind, with some niceties
# Jean Karim Bockstael - jkb@jkbockstael.be


# Import
from random import randint

# Gameplay constants
CODE_LENGTH = 4 # Length of the code (1-16)
CODE_COLORS = 10 # Number of different colors in the code (2-10)
MAX_GUESSES = 5 # Max number of guesses to find the correct code (1-50)
SHOW_MENU = True # Show main menu before playing a first game
EASY_MODE = True # Braindead mode

# String constants
STR_GUESS_PROMPT = 'Guess'
STR_WHITE_PEG = 'o'
STR_BLACK_PEG = 'x'
STR_EMPTY_PEG = '_'
STR_OUTCOME_WIN = 'Won!'
STR_OUTCOME_LOSS = 'Lost!'
STR_OUTCOME_REVEAL = 'The secret code was: '
STR_HELP = """
{codelength} digits long code, each between 0 and {codecolors} included, you have a maximum of {maxguesses} guesses to find it.
{whitepeg} : right digit, right position
{blackpeg} : right digit, wrong position
{emptypeg} : wrong digit
"""
STR_OPT_CODELENGTH = 'Number of digits in code (min 1 max 16): '
STR_OPT_CODECOLORS = 'Number of possible digits in code (min 2 max 10): '
STR_OPT_MAXGUESSES = 'Maximum number of guesses before giving up (min 1 max 50): '
STR_OPT_SHOWMENU = 'Show main menu on program startup? (False/True): '
STR_OPT_EASYMODE = 'Play in easy mode? (False/True): '
STR_MENU_MAIN = """
----------------
-- Mastermind --
----------------
A)bout
O)ptions
P)lay
Q)uit
"""
STR_MENU_MAINPROMPT = "Choice: "
STR_MENU_OPTIONS = """
------------------
-- Game Options --
------------------
"""
STR_ABOUT = """
----------------------
-- About Mastermind --

A simple and time-honored game, brought to your console using Python.

2009 - Jean Karim Bockstael - jkb@virus1984.com
"""


# And now, let the fun begin!
# (__)
# ( @@
# /\_| MOOH!


# Create a code of set length and number of colors, as a list of ints
def set_secret_code():
tmp_code = []
for i in range(0, CODE_LENGTH):
tmp_code.append(randint(0, CODE_COLORS - 1))
return tmp_code


# Read a code from the user
def get_guess_code():
tmp_guess = []
padding_spaces = ''
if (len(STR_GUESS_PROMPT) < CODE_LENGTH):
padding_spaces = " " * (CODE_LENGTH - len(STR_GUESS_PROMPT))
guess_prompt = STR_GUESS_PROMPT + padding_spaces + " : "
str_guess = raw_input(guess_prompt)
for i in range(0, CODE_LENGTH):
tmp_guess.append(int(str_guess[i]))
return tmp_guess


# Print a help message
def print_help():
print STR_HELP.format(codelength=CODE_LENGTH, codecolors=(CODE_COLORS-1), \
maxguesses=MAX_GUESSES, whitepeg=STR_WHITE_PEG, blackpeg=STR_BLACK_PEG, \
emptypeg=STR_EMPTY_PEG)


# Returns a code formatted for printing
def format_code(code):
formatted_code = ''
for i in range(0, CODE_LENGTH):
formatted_code += str(code[i])
return formatted_code


# Print a hint based on the player's guess
def print_hint(secret_code, guess_code):
hint = ''
if (EASY_MODE):
for i in range(0, CODE_LENGTH):
if (guess_code[i] == secret_code[i]):
hint += STR_WHITE_PEG
elif (guess_code[i] in secret_code):
hint += STR_BLACK_PEG
else:
hint += STR_EMPTY_PEG
else: # Badass mode
white_pegs = 0
black_pegs = 0
dupes = [False] * CODE_LENGTH
for i in range(0, CODE_LENGTH):
if (guess_code[i] == secret_code[i]):
white_pegs += 1
dupes[i] = True
else:
for j in range(0, CODE_LENGTH):
if (secret_code[j] == guess_code[i] and not dupes[j]):
black_pegs += 1
if (white_pegs != 0):
hint += str(white_pegs) + ' ' + STR_WHITE_PEG + ' '
if (black_pegs != 0):
hint += str(black_pegs) + ' ' + STR_BLACK_PEG
if (white_pegs == 0 and black_pegs == 0):
hint += STR_EMPTY_PEG
padding_spaces = ''
if (CODE_LENGTH < len(STR_GUESS_PROMPT)):
padding_spaces = " " * (len(STR_GUESS_PROMPT) - CODE_LENGTH)
print format_code(guess_code), padding_spaces + ':', hint


# Print the game outcome
def print_outcome(code_found, secret_code):
if (code_found):
print STR_OUTCOME_WIN
else:
print STR_OUTCOME_LOSS
print STR_OUTCOME_REVEAL, format_code(secret_code)


# Play a game of Mastermind
def play_game():
print_help()
secret_code = set_secret_code()
guess_num = 0
code_found = False
while (guess_num < MAX_GUESSES):
guess_code = get_guess_code()
guess_num += 1
code_found = (guess_code == secret_code)
if (code_found):
break # Avoid printing a hint if the code is found
print_hint(secret_code, guess_code)
print_outcome(code_found, secret_code)


# Options menu
def menu_options():
global CODE_LENGTH
global CODE_COLORS
global MAX_GUESSES
global SHOW_MENU
global EASY_MODE
print STR_MENU_OPTIONS
print STR_OPT_CODELENGTH
CODE_LENGTH = int(input("[" + str(CODE_LENGTH) + "] "))
print STR_OPT_CODECOLORS
CODE_COLORS = int(input("[" + str(CODE_COLORS) + "] "))
print STR_OPT_MAXGUESSES
MAX_GUESSES = int(input("[" + str(MAX_GUESSES) + "] "))
print STR_OPT_SHOWMENU
SHOW_MENU = input("[" + str(SHOW_MENU) + "] ")
print STR_OPT_EASYMODE
EASY_MODE = input("[" + str(EASY_MODE) + "] ")


# Main menu
def menu_main():
menu_main_choices = { "A" : show_about,
"O" : menu_options,
"P" : play_game,
"Q" : None }
usr_choice = ''
while (True):
print STR_MENU_MAIN
while (not usr_choice in menu_main_choices):
usr_choice = raw_input(STR_MENU_MAINPROMPT)
if (usr_choice == 'Q'):
return None
else:
menu_main_choices[usr_choice]()
usr_choice = ''


# Show "about" screen
def show_about():
print STR_ABOUT
raw_input()


# Main
if (SHOW_MENU):
menu_main()
else:
play_game()

# End



...la suite par ici...

14/05/09

"I know the pieces fit"

Houlà ça fait un furieux bail que je n'ai rien posté ici, on va finir par croire que j'ai vraiment une vie hyperactive de jeune cadre dynamique, ou que je me suis fait emporter par H1N1, au choix. Il est temps d'y remédier! Et histoire de varier les plaisirs je vais parler musique et mathématiques (légères, ne pas stresser), plus particulièrement de Tool.

Il y a quelques jours a surgi sur Reddit un lien vers une vidéo d'un fan de Tool montrant les curiosités mathématiques de leur morceau "Lateralus" extrait de l'album du même nom. La vidéo en question ne date pas d'hier et avait même été diggée quelques fois, mais le morceau est une pièce d'exception et il est toujours intéressant d'en découvrir les particularités.

Tool est un de ces groupes un peu monstrueux parce que chaque élément est une montagne de talent et de créativité à lui seul, mais qu'en plus une fois mis ensemble une curieuse alchimie fait que le groupe est supérieur à la somme de ses membres. En presque vingt ans d'activité ils ont sorti 4 albums (en 1993, 1996, 2001 et 2006), chacun étant clairement réfléchi, mûri et peaufiné pour atteindre un degré de perfection presque monstrueux. Leur chef-d'oeuvre incontesté reste à ce jour l'album Lateralus, sorti en 2001, catapulé en première place des ventes US dès sa sortie, et vainqueur d'un Grammy Award, et album de l'année selon Kerrang!, rien que ça...

La chanson Lateralus, 9 minutes et 24 secondes de bonheur, se fait un peu plus remarquer que le reste. La chanson parle de la quête de connaissance, de la libération de l'esprit sur le corps (on entendait déjà "This body holding me reminds me of my own mortality" sur Parabola) et culmine en la répétition de "Spiral out, keep going...". Pas grand-chose, mais si on est attentif aux pauses qui sont mises dans le chant du premier couplets, on observe ceci:

Black
then
white are
all I see
in my infancy.
Red and yellow then came to be,
reaching out to me.
Lets me see

As below, so above and beyond, I imagine.
Drawn beyond the lines of reason.
Push the envelope.
Watch it bend.

Soit en syllabes: 1, 1, 2, 3, 5, 8, 5, 3 puis 13, 8, 5, 3.

Après le refrain on reprend le même couplet mais avec un morceau qui manquait, et qui rend la structure nettement plus évidente:

Black
then
white are
all I see
in my infancy.
Red and yellow then came to be,
reaching out to me.
Lets me see

There is
so
much
more and
beckons me
to look through to these
infinite possibilities.

As below, so above and beyond, I imagine.
Drawn beyond the lines of reason.
Push the envelope.
Watch it bend.

Soit 1, 1, 2, 3, 5, 8, 5, 3, 2, 1, 1, 2, 3, 5, 8, 13, 8, 5, 3. Autrement dit, la suite de Fibonnaci dans le sens croissant puis décroissant sur ses premiers termes, deux fois. Ce qui, au vu du thème de la chanson et de la mentalité de son auteur, n'est absolument pas à attribuer au hasard. Un autre détail amusant? Le chant commence après 97 secondes de musique, soit après 1,618 minutes, 1,618 est le nombre d'or.

Waw.

Le refrain est sur une base rythmique de 9/8, puis 8/8, puis 7/8. 987 est un des termes de la suite de Fibonacci, mais le batteur Danny Carey a démenti que ce soit intentionnel, bien qu'il soit fasciné par les questions de numérologies et des géométries et que cela se ressente très nettement dans la complexité de son jeu.

L'album comporte 13 pistes, le terme de la série de Fibonnaci le plus grand du jeu rythmique de la plage titulaire. Une rumeur voulait que les pistes de l'album ne soient pas dans le "bon" ordre, et à cette question un fan a répondu en proposant un ordre de lecture différent et étonnament agréable. Son idée est que Parabol est un prélude à Parabola et sont respectivement 6ème et 7èmes pistes, donc au milieu du disque. Son arrangement commence par 6 et 7, puis continue par paires de nombres dont la somme vaut 13, le premier étant d'abord décroissant, puis croissant. Soit 6 et 7, 5 et 8, 4 et 9, 13, 1 et 12, 2 et 11, 3 et 10. L'ordre 6, 7, 5, 8, 4, 9, 13, 1, 12, 2, 11, 3, 10, baptisé The Holy Gift par son auteur, est effectivement troublant tellement il "coule" bien, mais il présente un petit hic: Tool joue toujours les morceaux Disposition, Reflection, et Triad ensemble et dans cet ordre, qui est l'ordre dans lequel ils apparaissent sur Lateralus, aux positions 10, 11, et 12. The Holy Gift casse ce triptique abruptement, ce qui peut laisser supposer que s'il existe un ordre parfait ce n'est pas celui-ci.

C'est tout de même troublant.

...la suite par ici...

16/04/09

Exercices de Michel Couprie: solutions aux séries 1 et 2, en Python

Eh oui, c'est la semaine de congé, du coup j'ai un peu levé le pied en matières informatiques. Mais pour ne pas laisser les choses en désuétude, voici quelque chose que j'avais fait avant le début du congé, partagé avec quelques favorisés, et qui pourrait être utile à d'autres.

Quand on veut apprendre à programmer, ou qu'on veut se faire la main sur un langage en particulier, on apprécie d'avoir à disposition des petits problèmes d'algorithmique de difficulté et de complexité croissantes. Pour ma part, quand je m'ennuie j'aime beaucoup avoir un problème que je peux résoudre en moins d'une heure, une sorte de "one-shot" pour se changer les idées.

En fouillant un peu j'ai trouvé cette liste de problèmes, proposé par Michel Couprie. ces problèmes (34 en tout) sont classés par difficulté croissante en quatre paliers. Voici mes solutions pour les problèmes des deux premiers paliers (les deux suivants suivront si je m'ennuie ce soir).


# Solutions aux exercices proposes par Michel Couprie a l'adresse:
# http://www.esiee.fr/~coupriem/Exos/exos/exos.html
#
# Il peut y avoir d'autres approches, evidemment, je ne fournis celles-ci qu'a
# titre d'exemples.
# 2009/04/08, 2009-04-09 - Jean Karim Bockstael - jkb@jkbockstael.be



#------------------------------------------------------------------------------
# DIFFICULTE 1
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# 01 - Factorielle
# http://www.esiee.fr/~coupriem/Exos/Enonces/fact

def factorielle_iterative(n):
res = 1
while (n > 1):
res *= n
n -= 1
return res

def factorielle_recursive(n):
if n < 2:
return 1
else:
return n * factorielle_recursive(n - 1)


#------------------------------------------------------------------------------
# 02 - Inversion d'un tableau
# http://www.esiee.fr/~coupriem/Exos/Enonces/inverse

def inversion_tableau_iterative(tab):
tmp = []
if len(tab) < 2:
return tab
for i in (len(tab), 0, -1):
tmp.append(tab[i - 1])
return tmp

def inversion_tableau_recursive(tab):
if len(tab) < 2:
return tab
else:
return inversion_tableau_recursive(tab[1:]) + [tab[0]]

def inversion_tableau_pythonienne(tab):
return tab[-1::-1]


#------------------------------------------------------------------------------
# 03 - Minimum et maximum sur un tableau en une seule passe
# http://www.esiee.fr/~coupriem/Exos/Enonces/minmax

def min_et_max(tab):
if len(tab) < 1:
return {}
res = {'min' : tab[0], 'max' : tab[0]}
for i in range(1, len(tab)):
if (tab[i] < res['min']):
res['min'] = tab[i]
if (tab[i] > res['max']):
res['max'] = tab[i]
return res


#------------------------------------------------------------------------------
# 04 - Palindrome ou non, en ignorant les espaces
# http://www.esiee.fr/~coupriem/Exos/Enonces/palindrome

def est_palindrome(texte):
if len(texte) < 2:
return True
tmp = texte.replace(' ', '')
return (tmp == tmp[-1::-1])


#------------------------------------------------------------------------------
# 05 - Solution d'un polynome par Horner
# http://www.esiee.fr/~coupriem/Exos/Enonces/polynome

def solution_horner(poly, value):
# avec poly de la forme [coeff, ...] sans vide, poids fort au debut
# donc on note explicitement les coefficiens nuls
result = poly[0]
for i in range(1, len(poly)):
result *= value
result += poly[i]
return result


#------------------------------------------------------------------------------
# 06 - Estimation de Pi
# http://www.esiee.fr/~coupriem/Exos/Enonces/calculpi

from random import random
from math import sqrt
def estimation_pi(nb_points):
def radius(x_coord, y_coord):
return sqrt(x_coord ** 2 + y_coord ** 2)
cnt = 0.0
for i in range(0, nb_points):
if radius(random(), random()) < 1:
cnt += 1
return cnt / nb_points * 4


#------------------------------------------------------------------------------
# 07 - Suite "cube de chiffres du terme precedent"
# http://www.esiee.fr/~coupriem/Exos/Enonces/cubes

def suite_cube_chiffres(depart):
def somme_cubes_chiffres(nombre):
tmp = str(nombre)
res = 0
for i in range(0, len(tmp)):
res += int(tmp[i]) ** 3
return res
if (depart % 3 != 0) or (depart < 0):
return "Le premier element doit etre un multiple positif de 3."
res = [depart]
while res[-1] != somme_cubes_chiffres(res[-1]):
res.append(somme_cubes_chiffres(res[-1]))
return res[-1]


#------------------------------------------------------------------------------
# 08 - Crible d'Eratosthene
# http://www.esiee.fr/~coupriem/Exos/Enonces/eratos

def crible_eratosthene(limite):
res_bool = [False, False]
for i in range(2, limite + 1):
res_bool.append(True)
for i in range(2, limite + 1):
for j in range(2, i / 2 + 1):
if (i % j == 0) and (i / j != 1):
res_bool[i] = False
res_num = []
for i in range(2, limite + 1):
if res_bool[i]:
res_num.append(i)
return res_num


#------------------------------------------------------------------------------
# 09 - Test de la primalite d'un entier
# http://www.esiee.fr/~coupriem/Exos/Enonces/premier

def est_premier(nombre):
if (nombre < 2):
return False
premiers = crible_erathosthene(nombre / 2 + 1)
for i in premiers:
if (nombre % i == 0):
return False
return True


#------------------------------------------------------------------------------
# 10 - Produit scalaire de deux vecteurs
# http://www.esiee.fr/~coupriem/Exos/Enonces/prodscal

def produit_scalaire(vec1, vec2):
if (len(vec1) != len(vec2)) or \
(len(vec1) < 1) or \
(len(vec2) < 1):
return "Arguments incorrects"
tmp = 0
for i in range(0, len(vec1)):
tmp += vec1[i] * vec2[i]
return tmp


#------------------------------------------------------------------------------
# 11 - Puissance N d'un nombre, en effectuant moins de N-1 multiplications
# http://www.esiee.fr/~coupriem/Exos/Enonces/puissance

def puissance(base, expo):
if (expo < 0):
return "L'exposant doit etre positif ou nul"
tmp = 1
while (expo > 1):
tmp *= (base * base)
expo -= 2
if (expo == 1):
tmp *= base
return tmp


#------------------------------------------------------------------------------
# 12 - Calcul de la racine carree
# http://www.esiee.fr/~coupriem/Exos/Enonces/raccar

def racine_carree(nbr, precision):
# Estimation a la louche
rac = 0
while (nbr > rac ** 2):
rac += 1
if (nbr == rac ** 2):
return rac
# Affinement
for i in range(0, precision):
rac = (rac + nbr / rac) / 2.0
return rac



#------------------------------------------------------------------------------
# 13 - Calcul de la racine cubique
# http://www.esiee.fr/~coupriem/Exos/Enonces/raccube

def racine_cubique(nbr, precision):
# Estimation a la louche
rac = 0
while (nbr > rac ** 3):
rac += 1
if (nbr == rac ** 3):
return rac
# Affinement
for i in range(0, precision):
rac = (2 * rac + nbr / (rac ** 2)) / 3.0
return rac


#------------------------------------------------------------------------------
# 14 - Recherche sequentielle sur un tableau
# http://www.esiee.fr/~coupriem/Exos/Enonces/rechseq
# Meme chose que l'exercice 03


#------------------------------------------------------------------------------
# 15 - Fonction sin(x)
# http://www.esiee.fr/~coupriem/Exos/Enonces/sinus

def sinus(x, precision):
def factorielle(n):
return factorielle_iterative(n)
result = 0.0
for n in range(0, precision):
result += ((-1) ** n) * ((x ** (2 * n + 1)) / (factorielle(2 * n + 1)))
return result


#------------------------------------------------------------------------------
# 16 - Symetrie d'une matrice
# http://www.esiee.fr/~coupriem/Exos/Enonces/symetrique

def est_symetrique(matrice):
if (len(matrice) != len(matrice[0])):
return False # Une matrice doit etre carree pour etre symetrique
for i in range(0, len(matrice)):
for j in range(0, i):
if matrice[i][j] != matrice[j][i]:
return False
return True


#------------------------------------------------------------------------------
# 17 - Affichage du triangle de Pascal
# http://www.esiee.fr/~coupriem/Exos/Enonces/trpascal

def triangle_de_pascal(rangees):
print "1"
print "1 1"
prevline = [1, 1]
for i in range(3, rangees + 1):
thisline = [1]
for j in range(1, i - 1):
thisline.append(prevline[j] + prevline[j - 1])
thisline.append(1)
for j in range(0, i - 1):
print str(thisline[j]) + " ",
print str(thisline[-1])
prevline = thisline




#------------------------------------------------------------------------------
# DIFFICULTE 2
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# 18 - Determiner si deux chaines sont anagrammes
# http://www.esiee.fr/~coupriem/Exos/Enonces/anagrame

def sont_anagrammes(chaine1, chaine2):
chaine1 = chaine1.strip(" ,.;:?!'\"-_").lower()
chaine2 = chaine2.strip(" ,.;:?!'\"-_").lower()
return (list(chaine1).sort() == list(chaine2).sort())


#------------------------------------------------------------------------------
# 19 - Convolution
# http://www.esiee.fr/~coupriem/Exos/Enonces/convolution

def convolution(tabA, tabH):
# A de taille 100x100, H de taille 7x7
tabB = [[0] * 100] * 100
for i in range(0, 100):
for j in range(0, 100):
if ((i in range(0, 3) or i in range(97, 100)) or \
(j in range(0, 3) or j in range(97, 100))):
tabB[i][j] = tabA[i][j]
else: # i,j in (4, 97)
for m in range(0, 7):
for n in range(0, 7):
tabB[i][j] += tabA[i + m - 3][j + n - 3] * tabH[m][n]
return tabB


#------------------------------------------------------------------------------
# 20 - Fusion de deux tableaux tries
# http://www.esiee.fr/~coupriem/Exos/Enonces/fusion

def fusion_tableaux_tries(tab1, tab2):
cur1 = 0
cur2 = 0
tab3 = []
while (cur1 < len(tab1)) and (cur2 < len(tab1)):
if tab1[cur1] < tab2[cur2]:
tab3.append(tab1[cur1])
cur1 += 1
else:
tab3.append(tab2[cur2])
cur2 +=1
# Un des deux tableaux a ete entierement copie, reste a vider l'autre
while (cur1 < len(tab1)):
tab3.append(tab1[cur1])
cur1 += 1
while (cur2 < len(tab2)):
tab3.append(tab2[cur2])
cur2 += 1
return tab3


#------------------------------------------------------------------------------
# 21 - Conjecture Hongroise (note: on l'appelle aussi "probleme de Collatz")
# http://www.esiee.fr/~coupriem/Exos/Enonces/hongrois

def hongroise(depart):
if (depart == 1):
print "1 4 2 1 4 2 ..."
else:
print str(depart),
if (depart % 2 == 0):
hongroise(depart / 2)
else:
hongroise(3 * depart + 1)


#------------------------------------------------------------------------------
# 22 - Regroupement des valeurs paires et impaires
# http://www.esiee.fr/~coupriem/Exos/Enonces/pairimpair

def paires_impaires(tab):
res = []
for i in range(0, len(tab)):
if (tab[i] % 2 == 0):
res.append(tab[i])
for i in range(0, len(tab)):
if (tab[i] % 2 != 0):
res.append(tab[i])
return res


#------------------------------------------------------------------------------
# 23 - Afficher les nombres parfaits compris entre 1 et N
# http://www.esiee.fr/~coupriem/Exos/Enonces/parfaits

def nombres_parfaits(limite):
res = []
for nb in range(1, limite + 1):
sommediv = 0
for di in range(1, nb / 2 + 1):
if (nb % di == 0):
sommediv += di
if (sommediv == nb):
res.append(nb)
return res


#------------------------------------------------------------------------------
# 24 - Determiner la periode d'un signal digital
# http://www.esiee.fr/~coupriem/Exos/Enonces/periode

def periode_signal(tab):
per = 0
fini = False
while (not fini) and (per < len(tab) - 1):
per +=1
# Verification de cette hypothese
for cur in range(0, per):
fini = (tab[cur] == tab[cur + per])
if (fini):
return per
else:
return 0


#------------------------------------------------------------------------------
# 25 - Plus grand plateau dans le graphique d'une fonction monotone
# http://www.esiee.fr/~coupriem/Exos/Enonces/plateau

def plus_grand_plateau(tab):
plat_max = 1
plat_tmp = 0
for i in range(1, len(tab)):
if tab[i] == tab[i - 1]:
plat_tmp += 1
else:
plat_tmp = 1
if plat_tmp > plat_max:
plat_max = plat_tmp
return plat_max


#------------------------------------------------------------------------------
# 26 - Calcul de la racine carree entiere d'un entier
# http://www.esiee.fr/~coupriem/Exos/Enonces/racent

def racine_carree_entiere(nbr):
rac = 0
while (nbr > rac ** 2):
rac += 1
if (nbr == rac ** 2):
return rac
else:
return rac - 1


#------------------------------------------------------------------------------
# 27 - Conversion Romain-arabe
# http://www.esiee.fr/~coupriem/Exos/Enonces/romains

def romain_vers_arabe(romannumber):
romandigits = { 'I': 1, 'V': 5, 'X': 10, 'L': 50 }
number = 0
for i in range(1, len(romannumber)):
if (romandigits[romannumber[i]] > romandigits[romannumber[i - 1]]):
number -= romandigits[romannumber[i - 1]]
else:
number += romandigits[romannumber[i - 1]]
number += romandigits[romannumber[-1]]
return digit


#------------------------------------------------------------------------------
# 28 - Transcodage octal-decimal
# http://www.esiee.fr/~coupriem/Exos/Enonces/transcodage

def octal_vers_decimal(octnum):
number = 0
octalnumber = str(octnum)
for i in range(0, len(octalnumber)):
number += int(octalnumber[i]) * (8 ** (len(octalnumber) - i - 1))
return number



...la suite par ici...