Last active
August 29, 2015 14:04
-
-
Save lkesteloot/4c3de075c9bea5c5bfea to your computer and use it in GitHub Desktop.
My first F# program! Generates simple expressions that evaluate to "near integers". These are numbers that are close to their nearest integer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generates simple expressions that evaluate to "near integers". These are numbers | |
// that are close to their nearest integer. Inspired by: | |
// | |
// http://ssodelta.wordpress.com/2014/08/01/the-quest-for-near-integers/ | |
// The numbers we calculate must be closer to their nearest integer than this | |
// value for them to be considered "near integers". | |
let eps = 0.0001 | |
// An expressions is one of these subtypes. | |
type Expr = | |
| Constant of int | |
| Pi | |
| E | |
| Sum of Expr * Expr | |
| Difference of Expr * Expr | |
| Product of Expr * Expr | |
| Quotient of Expr * Expr | |
| Power of Expr * Expr | |
| Sine of Expr | |
| Cosine of Expr | |
// Evaluates the Expr to a float. | |
let rec evaluate expr = | |
match expr with | |
| Constant c -> float c | |
| Pi -> System.Math.PI | |
| E -> System.Math.E | |
| Sum (a,b) -> evaluate a + evaluate b | |
| Difference (a,b) -> evaluate a - evaluate b | |
| Product (a,b) -> evaluate a * evaluate b | |
| Quotient (a,b) -> evaluate a / evaluate b | |
| Power (a,b) -> evaluate a ** evaluate b | |
| Sine a -> sin (evaluate a) | |
| Cosine a -> cos (evaluate a) | |
// Random number generator used to create random trees of expressions. | |
let rnd = new System.Random() | |
// Return a random expression tree of depth "depth", where a depth of 0 means | |
// a constant, a depth of 1 means a function of a constant, etc. | |
let rec makeRandomExpression depth = | |
match depth with | |
| 0 -> match (rnd.Next(1, 12)) with | |
| 10 -> Pi | |
| 11 -> E | |
| c -> Constant c | |
| _ -> match (rnd.Next(7)) with | |
| 0 -> Sum (makeRandomExpression (depth - 1), makeRandomExpression (depth - 1)) | |
| 1 -> Difference (makeRandomExpression (depth - 1), makeRandomExpression (depth - 1)) | |
| 2 -> Product (makeRandomExpression (depth - 1), makeRandomExpression (depth - 1)) | |
| 3 -> Quotient (makeRandomExpression (depth - 1), makeRandomExpression (depth - 1)) | |
| 4 -> Power (makeRandomExpression (depth - 1), makeRandomExpression 0) | |
| 5 -> Sine (makeRandomExpression (depth - 1)) | |
| 6 -> Cosine (makeRandomExpression (depth - 1)) | |
| _ -> Constant 0 // Can't happen -- here to suppress compiler warning. | |
// Format the expression tree as a string in normal mathematical notation. | |
let rec prettyPrint expr = | |
match expr with | |
| Constant c -> sprintf "%d" c | |
| Pi -> "π" | |
| E -> "e" | |
| Sum (a,b) -> sprintf "(%s + %s)" (prettyPrint a) (prettyPrint b) | |
| Difference (a,b) -> sprintf "(%s - %s)" (prettyPrint a) (prettyPrint b) | |
| Product (a,b) -> sprintf "(%s * %s)" (prettyPrint a) (prettyPrint b) | |
| Quotient (a,b) -> sprintf "(%s / %s)" (prettyPrint a) (prettyPrint b) | |
| Power (a,b) -> sprintf "(%s ** %s)" (prettyPrint a) (prettyPrint b) | |
| Sine a -> "sin " + prettyPrint a | |
| Cosine a -> "cos " + prettyPrint a | |
// Whether the float x is a "near integer", meaning that it's close to its | |
// closest integer. "Close" is defined as "closer than eps". | |
let isNearInteger x = | |
let rounded = round x | |
rounded <> 0.0 && rounded <> x && abs (rounded - x) < eps | |
// Generate a list of random expression trees. | |
let expressions = List.init 10000 (fun _ -> makeRandomExpression (rnd.Next(2, 4))) | |
// Evaluate them and keep the ones that generate near integers. | |
expressions |> | |
List.map (fun expr -> (expr, evaluate expr)) |> | |
List.filter (fun (expr, value) -> isNearInteger value) |> | |
List.map (fun (expr, value) -> sprintf "%s -> %.12f" (prettyPrint expr) value) |> | |
String.concat "\n" |> | |
printfn "%s" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment