Как писал Пад, это, по-видимому, расширение серии Тейлора cos ( x ) примерно x = 0:
косинус (x) = 1 - x² / 2! + х⁴ / 4! - х⁶ / 6! + ...
Итак, ваш вопрос - это вопрос XY: вы представили решение, а не поставили проблему. Вместо этого, представление проблемы значительно упрощает ее решение.
Давайте начнем с написания float
-специфической версии на F #:
let cosine n x =
let rec loop i q t c =
if i=n then c else
loop (i + 1) (q + 10 + 8*i) (-t * x * x / float q) (c + t)
loop 0 2 1.0 0.0
Например, мы можем вычислить 1M слагаемых расширения x = 0.1:
cosine 1000000 0.1
Лучший способ сделать эту полиморфную в F # - это параметризовать функцию по операторам, которые она использует, и пометить ее как inline
, чтобы снять издержки производительности при этой параметризации:
let inline cosine zero one ofInt ( ~-. ) ( +. ) ( *. ) ( /. ) n x =
let rec loop i q t c =
if i=n then c else
loop (i + 1) (q + 10 + 8*i) (-.t *. x *. x /. ofInt q) (c +. t)
loop 0 2 one zero
Теперь мы можем вычислить 1M терминов, используя float
, как это, что так же быстро, как и раньше:
cosine 0.0 1.0 float ( ~- ) (+) (*) (/) 1000000 0.1
Но мы также можем сделать с одинарной точностью float
:
cosine 0.0f 1.0f float32 ( ~- ) (+) (*) (/) 1000000 0.1f
И произвольная точность рациональна:
cosine 0N 1N BigNum.FromInt (~-) (+) (*) (/) 10 (1N / 10N)
И даже символично:
type Expr =
| Int of int
| Var of string
| Add of Expr * Expr
| Mul of Expr * Expr
| Pow of Expr * Expr
static member (~-) f = Mul(Int -1, f)
static member (+) (f, g) = Add(f, g)
static member (*) (f, g) = Mul(f, g)
static member (/) (f, g) = Mul(f, Pow(g, Int -1))
cosine (Int 0) (Int 1) Int (~-) (+) (*) (/) 3 (Var "x")
Чтобы сделать это быстрее, поднимите общее подвыражение -x*x
из loop
.