ocaml-programming

Simple OCaml programs
git clone git://git.laack.co/ocaml-programming.git
Log | Files | Refs | README

commit e5197c60ea61983cce2cd379f6c82ffc0563d366
parent df420b8a1796a09dc70089480210c5249b3527a1
Author: Andrew Laack <andrew@laack.co>
Date:   Wed, 19 Aug 2026 20:43:21 -0500

Busiest collatz + newton's sqrt method

Diffstat:
Ach1_self_learning/exercises_p2.ipynb | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 265 insertions(+), 0 deletions(-)

diff --git a/ch1_self_learning/exercises_p2.ipynb b/ch1_self_learning/exercises_p2.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ef154598-e0d1-4721-a171-f8cdb8340bc8", + "metadata": {}, + "outputs": [], + "source": [ + "(* 15\n", + "\n", + "NEW IDEA: recursion that stops when it is close enough, because floats cannot\n", + "be compared for equality.\n", + "\n", + "newton_sqrt x approximates the square root of x >= 0 by Newton's method. Start\n", + "from a guess and repeatedly improve it with\n", + "\n", + " next = (guess +. x /. guess) /. 2.\n", + "\n", + "Stop when the guess is good enough, when abs_float (guess *. guess -. x) is\n", + "below a small tolerance such as 1e-10. Note that x itself works as a starting\n", + "guess, except for x = 0.\n", + "\n", + "Do not write guess *. guess = x. Floats are approximations, that test would\n", + "loop forever, and it is the same reason 0.1 +. 0.2 = 0.3 is false in every\n", + "language with binary floats.\n", + "\n", + "newton_sqrt 2.0 is about 1.4142135, newton_sqrt 81.0 = 9.0,\n", + "newton_sqrt 0.0 = 0.0.\n", + "\n", + "Afterwards try newton_sqrt 1e12 and work out why an absolute tolerance of\n", + "1e-10 cannot terminate there. A double has about 16 significant digits, so near\n", + "1e12 the gap between neighbouring representable values is already larger than\n", + "1e-10. Fixing it means comparing relatively, for instance stopping when\n", + "successive guesses barely change.\n", + "\n", + "*)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "11e1e0c3-1f65-4251-998a-69804398e6a3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "val abs_diff : float -> float -> float = <fun>\n" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "text/plain": [ + "val newton_sqrt : float -> float = <fun>\n" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "let abs_diff x y = abs_float (x -. y);;\n", + "\n", + "let newton_sqrt x = \n", + " let rec go guess = \n", + " let diff = abs_diff x (guess *. guess) in\n", + " if diff < 0.0000000001\n", + " then guess\n", + " else go ((guess +. x /. guess) /. 2.)\n", + " in go x;;\n" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "1c13de25-3a65-4c53-be93-30aeaa43e3f4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "- : unit = ()\n", + "Findlib has been successfully loaded. Additional directives:\n", + " #require \"package\";; to load a package\n", + " #list;; to list the available packages\n", + " #camlp4o;; to load camlp4 (standard syntax)\n", + " #camlp4r;; to load camlp4 (revised syntax)\n", + " #predicates \"p,q,...\";; to set these predicates\n", + " Topfind.reset();; to force that packages will be reloaded\n", + " #thread;; to enable threads\n", + "\n", + "- : unit = ()\n" + ] + } + ], + "source": [ + "#use \"topfind\";;\n", + "#require \"qcheck\";;" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "c54a0a4c-a9f0-4ebd-bd59-d7fc331b51ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "val abs_diff : float -> float -> float = <fun>\n" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "let abs_diff x y = abs_float (x -. y);;" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "3bc48b8e-6aee-4438-9db0-561c4045ce99", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "- : float = 2.00000000000451061\n" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "newton_sqrt 2. *. newton_sqrt 2." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "f307630e-b1a1-45a1-a42f-6a934f0602dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "- : bool = true\n" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(abs_diff 2. ((newton_sqrt 2.) *. (newton_sqrt 2.))) < 0.01" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "04f59f1f-fbb1-40f3-a8e8-67dc1aa54231", + "metadata": {}, + "outputs": [], + "source": [ + "(* 16\n", + "\n", + "NEW IDEA: two accumulators tracking the best answer so far, the functional\n", + "version of keeping a running maximum.\n", + "\n", + "busiest_collatz lo hi returns which n in the range lo..hi takes the most\n", + "Collatz steps to reach 1. On a tie, return the smallest such n.\n", + "\n", + "*)" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "id": "2030e995-98d6-4ca4-b450-d50004487746", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "val busiest_collatz : int -> int -> int = <fun>\n" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "let busiest_collatz lo hi = \n", + " let rec col_calc n = \n", + " if n = 1 then 1 else\n", + " if n mod 2 = 0 \n", + " then ((col_calc (n / 2))) + 1\n", + " else ((col_calc ((3 * n) + 1))) + 1\n", + " in \n", + " let rec go best_num best_count current_num =\n", + " if current_num < lo then best_num\n", + " else\n", + " let current_count = (col_calc current_num) in\n", + " if current_count >= best_count\n", + " then go current_num current_count (current_num - 1)\n", + " else\n", + " go best_num best_count (current_num - 1)\n", + " in go 0 0 hi" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "id": "a17b339d-0d3b-455c-8f31-2c6d10251134", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "- : int = 837799\n" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "busiest_collatz 1 1000000" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "OCaml default", + "language": "OCaml", + "name": "ocaml-jupyter" + }, + "language_info": { + "codemirror_mode": "text/x-ocaml", + "file_extension": ".ml", + "mimetype": "text/x-ocaml", + "name": "OCaml", + "nbconverter_exporter": null, + "pygments_lexer": "OCaml", + "version": "4.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}