(* Author: Johannes Hoelzl, TU Muenchen Coercions removed by Dmitriy Traytel This file contains only general material about computing lower/upper bounds on real functions. Approximation.thy contains the actual approximation algorithm and the approximation oracle. This is in order to make a clear separation between "morally immaculate" material about upper/lower bounds and the trusted oracle/reflection. *)
theory Approximation_Bounds imports
Complex_Main "HOL-Library.Interval_Float"
Dense_Linear_Order begin
primrec horner :: "(nat ==> nat) ==> (nat ==> nat ==> nat) ==> nat ==> nat ==> nat ==> real ==> real"where "horner F G 0 i k x = 0" | "horner F G (Suc n) i k x = 1 / k - x * horner F G n (F i) (G i k) x"
lemma horner_schema': fixes x :: real and a :: "nat ==> real" shows"a 0 - x * (∑ i=0..∑ i=0.. proof - have shift_pow: "∧i. - (x * ((-1)^i * a (Suc i) * x ^ i)) = (-1)^(Suc i) * a (Suc i) * x ^ (Suc i)" by auto show ?thesis unfolding sum_distrib_left shift_pow uminus_add_conv_diff [symmetric] sum_negf[symmetric]
sum.atLeast_Suc_lessThan[OF zero_less_Suc]
sum.reindex[OF inj_Suc, unfolded comp_def, symmetric, of "λ n. (-1)^n *a n * x^n"] by auto qed
lemma horner_schema: fixes f :: "nat ==> nat"and G :: "nat ==> nat ==> nat"and F :: "nat ==> nat" assumes f_Suc: "∧n. f (Suc n) = G ((F ^^ n) s) (f n)" shows"horner F G n ((F ^^ j') s) (f j') x = (∑ j = 0..< n. (- 1) ^ j * (1 / (f (j' + j))) * x ^ j)" proof (induct n arbitrary: j') case 0 thenshow ?caseby auto next case (Suc n) show ?caseunfolding horner.simps Suc[where j'="Suc j'", unfolded funpow.simps comp_def f_Suc] using horner_schema'[of "λ j. 1 / (f (j' + j))"] by auto qed
lemma horner_bounds': fixes lb :: "nat ==> nat ==> nat ==> float ==> float"and ub :: "nat ==> nat ==> nat ==> float ==> float" assumes"0 ≤ real_of_float x"and f_Suc: "∧n. f (Suc n) = G ((F ^^ n) s) (f n)" and lb_0: "∧ i k x. lb 0 i k x = 0" and lb_Suc: "∧ n i k x. lb (Suc n) i k x = float_plus_down prec (lapprox_rat prec 1 k) (- float_round_up prec (x * (ub n (F i) (G i k) x)))" and ub_0: "∧ i k x. ub 0 i k x = 0" and ub_Suc: "∧ n i k x. ub (Suc n) i k x = float_plus_up prec (rapprox_rat prec 1 k) (- float_round_down prec (x * (lb n (F i) (G i k) x)))" shows"(lb n ((F ^^ j') s) (f j') x) ≤ horner F G n ((F ^^ j') s) (f j') x ∧ horner F G n ((F ^^ j') s) (f j') x ≤ (ub n ((F ^^ j') s) (f j') x)"
(is"?lb n j' ≤ ?horner n j' ∧ ?horner n j' ≤ ?ub n j'") proof (induct n arbitrary: j') case 0 thus ?caseunfolding lb_0 ub_0 horner.simps by auto next case (Suc n) thus ?caseusing lapprox_rat[of prec 1 "f j'"] using rapprox_rat[of 1 "f j'" prec]
Suc[where j'="Suc j'"] ‹0 ≤ real_of_float x› by (auto intro!: add_mono mult_left_mono float_round_down_le float_round_up_le
order_trans[OF add_mono[OF _ float_plus_down_le]]
order_trans[OF _ add_mono[OF _ float_plus_up_le]]
simp add: lb_Suc ub_Suc field_simps f_Suc) qed
subsection"Theorems for floating point functions implementing the horner scheme"
text‹ Here 🪙‹f :: nat ==> nat›is the sequence defining the Taylor series, the coefficients are all alternating and reciprocs. We use 🍋‹G›and 🍋‹F› to describe the computation of 🍋‹f›. ›
lemma horner_bounds: fixes F :: "nat ==> nat"and G :: "nat ==> nat ==> nat" assumes"0 ≤ real_of_float x"and f_Suc: "∧n. f (Suc n) = G ((F ^^ n) s) (f n)" and lb_0: "∧ i k x. lb 0 i k x = 0" and lb_Suc: "∧ n i k x. lb (Suc n) i k x = float_plus_down prec (lapprox_rat prec 1 k) (- float_round_up prec (x * (ub n (F i) (G i k) x)))" and ub_0: "∧ i k x. ub 0 i k x = 0" and ub_Suc: "∧ n i k x. ub (Suc n) i k x = float_plus_up prec (rapprox_rat prec 1 k) (- float_round_down prec (x * (lb n (F i) (G i k) x)))" shows"(lb n ((F ^^ j') s) (f j') x) ≤ (∑j=0..
(is"?lb") and"(∑j=0..≤ (ub n ((F ^^ j') s) (f j') x)"
(is"?ub") proof - have"?lb ∧ ?ub" using horner_bounds'[where lb=lb, OF ‹0 ≤ real_of_float x› f_Suc lb_0 lb_Suc ub_0 ub_Suc] unfolding horner_schema[where f=f, OF f_Suc] by simp thus"?lb"and"?ub"by auto qed
lemma horner_bounds_nonpos: fixes F :: "nat ==> nat"and G :: "nat ==> nat ==> nat" assumes"real_of_float x ≤ 0"and f_Suc: "∧n. f (Suc n) = G ((F ^^ n) s) (f n)" and lb_0: "∧ i k x. lb 0 i k x = 0" and lb_Suc: "∧ n i k x. lb (Suc n) i k x = float_plus_down prec (lapprox_rat prec 1 k) (float_round_down prec (x * (ub n (F i) (G i k) x)))" and ub_0: "∧ i k x. ub 0 i k x = 0" and ub_Suc: "∧ n i k x. ub (Suc n) i k x = float_plus_up prec (rapprox_rat prec 1 k) (float_round_up prec (x * (lb n (F i) (G i k) x)))" shows"(lb n ((F ^^ j') s) (f j') x) ≤ (∑j=0.. (is"?lb") and"(∑j=0..≤ (ub n ((F ^^ j') s) (f j') x)" (is"?ub") proof - have diff_mult_minus: "x - y * z = x + - y * z"for x y z :: float by simp have sum_eq: "(∑j=0.. (∑j = 0.. by (auto simp add: field_simps power_mult_distrib[symmetric]) have"0 ≤ real_of_float (-x)"using assms by auto from horner_bounds[where G=G and F=F and f=f and s=s and prec=prec and lb="λ n i k x. lb n i k (-x)"and ub="λ n i k x. ub n i k (-x)",
unfolded lb_Suc ub_Suc diff_mult_minus,
OF this f_Suc lb_0 _ ub_0 _] show"?lb"and"?ub"unfolding minus_minus sum_eq by (auto simp: minus_float_round_up_eq minus_float_round_down_eq) qed
subsection‹Selectors for next even or odd number›
text‹ The horner scheme computes alternating series. To get the upper and lower bounds we need to guarantee to access a even or odd member. To do this we use 🍋‹get_odd›and 🍋‹get_even›. ›
definition get_odd :: "nat ==> nat"where "get_odd n = (if odd n then n else (Suc n))"
definition get_even :: "nat ==> nat"where "get_even n = (if even n then n else (Suc n))"
lemma get_odd[simp]: "odd (get_odd n)" unfolding get_odd_def by (cases "odd n") auto
lemma get_even[simp]: "even (get_even n)" unfolding get_even_def by (cases "even n") auto
lemma get_odd_ex: "∃ k. Suc k = get_odd n ∧ odd (Suc k)" by (auto simp: get_odd_def odd_pos intro!: exI[of _ "n - 1"])
lemma get_even_double: "∃i. get_even n = 2 * i" using get_even by (blast elim: evenE)
lemma get_odd_double: "∃i. get_odd n = 2 * i + 1" using get_odd by (blast elim: oddE)
section"Power function"
definition float_power_bnds :: "nat ==> nat ==> float ==> float ==> float * float"where "float_power_bnds prec n l u = (if 0 < l then (power_down_fl prec l n, power_up_fl prec u n) else if odd n then (- power_up_fl prec ∣l∣ n, if u < 0 then - power_down_fl prec ∣u∣ n else power_up_fl prec u n) else if u < 0 then (power_down_fl prec ∣u∣ n, power_up_fl prec ∣l∣ n) else (0, power_up_fl prec (max ∣l∣∣u∣) n))"
lemma le_minus_power_downI: "0 ≤ x ==> x ^ n ≤ - a ==> a ≤ - power_down prec x n" by (subst le_minus_iff) (auto intro: power_down_le power_mono_odd)
lemma float_power_bnds: "(l1, u1) = float_power_bnds prec n l u ==> x ∈ {l .. u} ==> (x::real) ^ n ∈ {l1..u1}" by (auto
simp: float_power_bnds_def max_def real_power_up_fl real_power_down_fl minus_le_iff
split: if_split_asm
intro!: power_up_le power_down_le le_minus_power_downI
intro: power_mono_odd power_mono power_mono_even zero_le_even_power)
lemma bnds_power: "∀(x::real) l u. (l1, u1) = float_power_bnds prec n l u ∧ x ∈ {l .. u} ⟶ l1 ≤ x ^ n ∧ x ^ n ≤ u1" using float_power_bnds by auto
lift_definition power_float_interval :: "nat ==> nat ==> float interval ==> float interval" is"λp n (l, u). float_power_bnds p n l u" using float_power_bnds by (auto simp: bnds_power dest!: float_power_bnds[OF sym])
lemma lower_power_float_interval: "lower (power_float_interval p n x) = fst (float_power_bnds p n (lower x) (upper x))" by transfer auto lemma upper_power_float_interval: "upper (power_float_interval p n x) = snd (float_power_bnds p n (lower x) (upper x))" by transfer auto
lemma power_float_intervalI: "x ∈🪙r X ==> x ^ n ∈🪙r power_float_interval p n X" using float_power_bnds[OF prod.collapse] by (auto simp: set_of_eq lower_power_float_interval upper_power_float_interval)
lemma power_float_interval_mono: "set_of (power_float_interval prec n A) ⊆ set_of (power_float_interval prec n B)" if"set_of A ⊆ set_of B" proof -
define la where"la = real_of_float (lower A)"
define ua where"ua = real_of_float (upper A)"
define lb where"lb = real_of_float (lower B)"
define ub where"ub = real_of_float (upper B)" have ineqs: "lb ≤ la""la ≤ ua""ua ≤ ub""lb ≤ ub" using that lower_le_upper[of A] lower_le_upper[of B] by (auto simp: la_def ua_def lb_def ub_def set_of_eq) show ?thesis using ineqs by (simp add: set_of_subset_iff float_power_bnds_def max_def
power_down_fl.rep_eq power_up_fl.rep_eq
lower_power_float_interval upper_power_float_interval
la_def[symmetric] ua_def[symmetric] lb_def[symmetric] ub_def[symmetric])
(auto intro!: power_down_mono power_up_mono intro: order_trans[where y=0]) qed
lemma lower_plus_float_interval: "lower (plus_float_interval prec ivl ivl') = float_plus_down prec (lower ivl) (lower ivl')" by transfer auto lemma upper_plus_float_interval: "upper (plus_float_interval prec ivl ivl') = float_plus_up prec (upper ivl) (upper ivl')" by transfer auto
lemma mult_float_interval_ge: "real_interval A + real_interval B ≤ real_interval (plus_float_interval prec A B)" unfolding less_eq_interval_def by transfer
(auto simp: lower_plus_float_interval upper_plus_float_interval
intro!: order.trans[OF float_plus_down] order.trans[OF _ float_plus_up])
lemma plus_float_interval: "set_of (real_interval A) + set_of (real_interval B) ⊆ set_of (real_interval (plus_float_interval prec A B))" proof - have"set_of (real_interval A) + set_of (real_interval B) ⊆ set_of (real_interval A + real_interval B)" by (simp add: set_of_plus) alsohave"…⊆ set_of (real_interval (plus_float_interval prec A B))" using mult_float_interval_ge[of A B prec] by (simp add: set_of_subset_iff') finallyshow ?thesis . qed
lemma plus_float_intervalI: "x + y ∈🪙r plus_float_interval prec A B" if"x ∈🪙i real_interval A""y ∈🪙i real_interval B" using plus_float_interval[of A B] that by auto
lemma plus_float_interval_mono: "plus_float_interval prec A B ≤ plus_float_interval prec X Y" if"A ≤ X""B ≤ Y" using that by (auto simp: less_eq_interval_def lower_plus_float_interval upper_plus_float_interval
float_plus_down.rep_eq float_plus_up.rep_eq plus_down_mono plus_up_mono)
lemma lower_mult_float_interval: "lower (mult_float_interval p x y) = fst (bnds_mult p (lower x) (upper x) (lower y) (upper y))" by transfer auto lemma upper_mult_float_interval: "upper (mult_float_interval p x y) = snd (bnds_mult p (lower x) (upper x) (lower y) (upper y))" by transfer auto
lemma mult_float_interval: "set_of (real_interval A) * set_of (real_interval B) ⊆ set_of (real_interval (mult_float_interval prec A B))" proof - let ?bm = "bnds_mult prec (lower A) (upper A) (lower B) (upper B)" show ?thesis using bnds_mult[of "fst ?bm""snd ?bm", simplified, OF refl] by (auto simp: set_of_eq set_times_def upper_mult_float_interval lower_mult_float_interval) qed
lemma mult_float_intervalI: "x * y ∈🪙r mult_float_interval prec A B" if"x ∈🪙i real_interval A""y ∈🪙i real_interval B" using mult_float_interval[of A B] that by auto
lemma mult_float_interval_mono': "set_of (mult_float_interval prec A B) ⊆ set_of (mult_float_interval prec X Y)" if"set_of A ⊆ set_of X""set_of B ⊆ set_of Y" using that apply transfer unfolding bnds_mult_def atLeastatMost_subset_iff float_plus_down.rep_eq float_plus_up.rep_eq by (auto simp: float_plus_down.rep_eq float_plus_up.rep_eq mult_float_mono1 mult_float_mono2)
lemma mult_float_interval_mono: "mult_float_interval prec A B ≤ mult_float_interval prec X Y" if"A ≤ X""B ≤ Y" using mult_float_interval_mono'[of A X B Y prec] that by (simp add: set_of_subset_iff')
lemma map_bnds: assumes"(lf, uf) = map_bnds lb ub prec (l, u)" assumes"mono f" assumes"x ∈ {real_of_float l..real_of_float u}" assumes"real_of_float (lb prec l) ≤ f (real_of_float l)" assumes"real_of_float (ub prec u) ≥ f (real_of_float u)" shows"f x ∈ {real_of_float lf..real_of_float uf}" proof - from assms have"real_of_float lf = real_of_float (lb prec l)" by (simp add: map_bnds_def) alsohave"real_of_float (lb prec l) ≤ f (real_of_float l)"by fact alsofrom assms have"…≤ f x" by (intro monoD[OF ‹mono f›]) auto finallyhave lf: "real_of_float lf ≤ f x" .
from assms have"f x ≤ f (real_of_float u)" by (intro monoD[OF ‹mono f›]) auto alsohave"…≤ real_of_float (ub prec u)"by fact alsofrom assms have"… = real_of_float uf" by (simp add: map_bnds_def) finallyhave uf: "f x ≤ real_of_float uf" .
from lf uf show ?thesis by simp qed
section"Square root"
text‹ The square root computation is implemented as newton iteration. As first first step we use the nearest power of two greater than the square root. ›
fun sqrt_iteration :: "nat ==> nat ==> float ==> float"where "sqrt_iteration prec 0 x = Float 1 ((bitlen ∣mantissa x∣ + exponent x) div 2 + 1)" | "sqrt_iteration prec (Suc m) x = (let y = sqrt_iteration prec m x in Float 1 (- 1) * float_plus_up prec y (float_divr prec x y))"
lemma compute_sqrt_iteration_base[code]: shows"sqrt_iteration prec n (Float m e) = (if n = 0 then Float 1 ((if m = 0 then 0 else bitlen ∣m∣ + e) div 2 + 1) else (let y = sqrt_iteration prec (n - 1) (Float m e) in Float 1 (- 1) * float_plus_up prec y (float_divr prec (Float m e) y)))" using bitlen_Float by (cases n) simp_all
function ub_sqrt lb_sqrt :: "nat ==> float ==> float"where "ub_sqrt prec x = (if 0 < x then (sqrt_iteration prec prec x) else if x < 0 then - lb_sqrt prec (- x) else 0)" | "lb_sqrt prec x = (if 0 < x then (float_divl prec x (sqrt_iteration prec prec x)) else if x < 0 then - ub_sqrt prec (- x) else 0)" by pat_completeness auto terminationby (relation "measure (λ v. let (prec, x) = case_sum id id v in (if x < 0 then 1 else 0))", auto)
lemma sqrt_ub_pos_pos_1: assumes"sqrt x < b"and"0 < b"and"0 < x" shows"sqrt x < (b + x / b)/2" proof - from assms have"0 < (b - sqrt x)🪙2 "by simp alsohave"… = b🪙2 - 2 * b * sqrt x + (sqrt x)🪙2"by algebra alsohave"… = b🪙2 - 2 * b * sqrt x + x"using assms by simp finallyhave"0 < b🪙2 - 2 * b * sqrt x + x" . hence"0 < b / 2 - sqrt x + x / (2 * b)"using assms by (simp add: field_simps power2_eq_square) thus ?thesis by (simp add: field_simps) qed
lemma sqrt_iteration_bound: assumes"0 < real_of_float x" shows"sqrt x < sqrt_iteration prec n x" proof (induct n) case 0 show ?case proof (cases x) case (Float m e) hence"0 < m" using assms by (auto simp: algebra_split_simps) hence"0 < sqrt m"by auto
have int_nat_bl: "(nat (bitlen m)) = bitlen m" using bitlen_nonneg by auto
have"x = (m / 2^nat (bitlen m)) * 2 powr (e + (nat (bitlen m)))" unfolding Float by (auto simp: powr_realpow[symmetric] field_simps powr_add) alsohave"… < 1 * 2 powr (e + nat (bitlen m))" proof (rule mult_strict_right_mono, auto) show"m < 2^nat (bitlen m)" using bitlen_bounds[OF ‹0 🚫›, THEN conjunct2] unfolding of_int_less_iff[of m, symmetric] by auto qed finallyhave"sqrt x < sqrt (2 powr (e + bitlen m))" unfolding int_nat_bl by auto alsohave"…≤ 2 powr ((e + bitlen m) div 2 + 1)" proof - let ?E = "e + bitlen m" have E_mod_pow: "2 powr (?E mod 2) < 4" proof (cases "?E mod 2 = 1") case True thus ?thesis by auto next case False have"0 ≤ ?E mod 2"by auto have"?E mod 2 < 2"by auto from this[THEN zless_imp_add1_zle] have"?E mod 2 ≤ 0"using False by auto from xt1(5)[OF ‹0 ≤ ?E mod 2› this] show ?thesis by auto qed hence"sqrt (2 powr (?E mod 2)) < sqrt (2 * 2)" by (intro real_sqrt_less_mono) auto hence E_mod_pow: "sqrt (2 powr (?E mod 2)) < 2"by auto
have E_eq: "2 powr ?E = 2 powr (?E div 2 + ?E div 2 + ?E mod 2)" by auto have"sqrt (2 powr ?E) = sqrt (2 powr (?E div 2) * 2 powr (?E div 2) * 2 powr (?E mod 2))" unfolding E_eq unfolding powr_add[symmetric] by (metis of_int_add) alsohave"… = 2 powr (?E div 2) * sqrt (2 powr (?E mod 2))" unfolding real_sqrt_mult[of _ "2 powr (?E mod 2)"] real_sqrt_abs2 by auto alsohave"… < 2 powr (?E div 2) * 2 powr 1" by (rule mult_strict_left_mono) (auto intro: E_mod_pow) alsohave"… = 2 powr (?E div 2 + 1)" unfolding add.commute[of _ 1] powr_add[symmetric] by simp finallyshow ?thesis by auto qed finallyshow ?thesis using‹0 🚫› unfolding Float by (subst compute_sqrt_iteration_base) (simp add: ac_simps) qed next case (Suc n) let ?b = "sqrt_iteration prec n x" have"0 < sqrt x" using‹0 🚫 x›by auto alsohave"… < real_of_float ?b" using Suc . finallyhave"sqrt x < (?b + x / ?b)/2" using sqrt_ub_pos_pos_1[OF Suc _ ‹0 🚫 x›] by auto alsohave"…≤ (?b + (float_divr prec x ?b))/2" by (rule divide_right_mono, auto simp add: float_divr) alsohave"… = (Float 1 (- 1)) * (?b + (float_divr prec x ?b))" by simp alsohave"…≤ (Float 1 (- 1)) * (float_plus_up prec ?b (float_divr prec x ?b))" by (auto simp add: algebra_simps float_plus_up_le) finallyshow ?case unfolding sqrt_iteration.simps Let_def distrib_left . qed
lemma sqrt_iteration_lower_bound: assumes"0 < real_of_float x" shows"0 < real_of_float (sqrt_iteration prec n x)" (is"0 < ?sqrt") proof - have"0 < sqrt x"using assms by auto alsohave"… < ?sqrt"using sqrt_iteration_bound[OF assms] . finallyshow ?thesis . qed
lemma lb_sqrt_lower_bound: assumes"0 ≤ real_of_float x" shows"0 ≤ real_of_float (lb_sqrt prec x)" proof (cases "0 < x") case True hence"0 < real_of_float x"and"0 ≤ x" using‹0 ≤ real_of_float x›by auto hence"0 < sqrt_iteration prec prec x" using sqrt_iteration_lower_bound by auto hence"0 ≤ real_of_float (float_divl prec x (sqrt_iteration prec prec x))" using float_divl_lower_bound[OF ‹0 ≤ x›] unfolding less_eq_float_def by auto thus ?thesis unfolding lb_sqrt.simps using True by auto next case False with‹0 ≤ real_of_float x›have"real_of_float x = 0"by auto thus ?thesis unfolding lb_sqrt.simps by auto qed
lemma bnds_sqrt': "sqrt x ∈ {(lb_sqrt prec x) .. (ub_sqrt prec x)}" proof - have lb: "lb_sqrt prec x ≤ sqrt x"if"0 < x"for x :: float proof - from that have"0 < real_of_float x"and"0 ≤ real_of_float x"by auto hence sqrt_gt0: "0 < sqrt x"by auto hence sqrt_ub: "sqrt x < sqrt_iteration prec prec x" using sqrt_iteration_bound by auto have"(float_divl prec x (sqrt_iteration prec prec x)) ≤ x / (sqrt_iteration prec prec x)"by (rule float_divl) alsohave"… < x / sqrt x" by (rule divide_strict_left_mono[OF sqrt_ub ‹0 🚫 x›
mult_pos_pos[OF order_less_trans[OF sqrt_gt0 sqrt_ub] sqrt_gt0]]) alsohave"… = sqrt x" unfolding inverse_eq_iff_eq[of _ "sqrt x", symmetric]
sqrt_divide_self_eq[OF ‹0 ≤ real_of_float x›, symmetric] by auto finallyshow ?thesis unfolding lb_sqrt.simps if_P[OF ‹0 🚫›] by auto qed have ub: "sqrt x ≤ ub_sqrt prec x"if"0 < x"for x :: float proof - from that have"0 < real_of_float x"by auto hence"0 < sqrt x"by auto hence"sqrt x < sqrt_iteration prec prec x" using sqrt_iteration_bound by auto thenshow ?thesis unfolding ub_sqrt.simps if_P[OF ‹0 🚫›] by auto qed show ?thesis using lb[of "-x"] ub[of "-x"] lb[of x] ub[of x] by (auto simp add: lb_sqrt.simps ub_sqrt.simps real_sqrt_minus) qed
lemma bnds_sqrt: "∀(x::real) lx ux. (l, u) = (lb_sqrt prec lx, ub_sqrt prec ux) ∧ x ∈ {lx .. ux} ⟶ l ≤ sqrt x ∧ sqrt x ≤ u" proof ((rule allI) +, rule impI, erule conjE, rule conjI) fix x :: real fix lx ux assume"(l, u) = (lb_sqrt prec lx, ub_sqrt prec ux)" and x: "x ∈ {lx .. ux}" hence l: "l = lb_sqrt prec lx "and u: "u = ub_sqrt prec ux"by auto
have"sqrt lx ≤ sqrt x"using x by auto from order_trans[OF _ this] show"l ≤ sqrt x"unfolding l using bnds_sqrt'[of lx prec] by auto
have"sqrt x ≤ sqrt ux"using x by auto from order_trans[OF this] show"sqrt x ≤ u"unfolding u using bnds_sqrt'[of ux prec] by auto qed
lift_definition sqrt_float_interval::"nat ==> float interval ==> float interval" is"λprec. λ(lx, ux). (lb_sqrt prec lx, ub_sqrt prec ux)" using bnds_sqrt' by auto (meson order_trans real_sqrt_le_iff)
lemma lower_float_interval: "lower (sqrt_float_interval prec X) = lb_sqrt prec (lower X)" by transfer auto
lemma upper_float_interval: "upper (sqrt_float_interval prec X) = ub_sqrt prec (upper X)" by transfer auto
lemma sqrt_float_intervalI: "sqrt x ∈🪙r sqrt_float_interval p X"if"x ∈🪙r X" using sqrt_float_interval[of X p] that by auto
section"Arcus tangens and π"
subsection"Compute arcus tangens series"
text‹ As first step we implement the computation of the arcus tangens series. This is only valid in the range 🍋‹{-1 :: real .. 1}›. This is used to compute π and then the entire arcus tangens. ›
fun ub_arctan_horner :: "nat ==> nat ==> nat ==> float ==> float" and lb_arctan_horner :: "nat ==> nat ==> nat ==> float ==> float"where "ub_arctan_horner prec 0 k x = 0"
| "ub_arctan_horner prec (Suc n) k x = float_plus_up prec (rapprox_rat prec 1 k) (- float_round_down prec (x * (lb_arctan_horner prec n (k + 2) x)))"
| "lb_arctan_horner prec 0 k x = 0"
| "lb_arctan_horner prec (Suc n) k x = float_plus_down prec (lapprox_rat prec 1 k) (- float_round_up prec (x * (ub_arctan_horner prec n (k + 2) x)))"
lemma arctan_0_1_bounds': assumes"0 ≤ real_of_float y""real_of_float y ≤ 1" and"even n" shows"arctan (sqrt y) ∈ {(sqrt y * lb_arctan_horner prec n 1 y) .. (sqrt y * ub_arctan_horner prec (Suc n) 1 y)}" proof - let ?c = "λi. (- 1) ^ i * (1 / (i * 2 + (1::nat)) * sqrt y ^ (i * 2 + 1))" let ?S = "λn. ∑ i=0..
have"0 ≤ sqrt y"using assms by auto have"sqrt y ≤ 1"using assms by auto from‹even n›obtain m where"2 * m = n"by (blast elim: evenE)
have"arctan (sqrt y) ∈ { ?S n .. ?S (Suc n) }" proof (cases "sqrt y = 0") case True thenshow ?thesis by simp next case False hence"0 < sqrt y"using‹0 ≤ sqrt y›by auto hence prem: "0 < 1 / (0 * 2 + (1::nat)) * sqrt y ^ (0 * 2 + 1)"by auto
have"∣ sqrt y ∣≤ 1"using‹0 ≤ sqrt y›‹sqrt y ≤ 1›by auto from mp[OF summable_Leibniz(2)[OF zeroseq_arctan_series[OF this]
monoseq_arctan_series[OF this]] prem, THEN spec, of m, unfolded ‹2 * m = n›] show ?thesis unfolding arctan_series[OF ‹∣ sqrt y ∣≤ 1›] Suc_eq_plus1 atLeast0LessThan . qed note arctan_bounds = this[unfolded atLeastAtMost_iff]
have F: "∧n. 2 * Suc n + 1 = 2 * n + 1 + 2"by auto
note bounds = horner_bounds[where s=1 and f="λi. 2 * i + 1"and j'=0 and lb="λn i k x. lb_arctan_horner prec n k x" and ub="λn i k x. ub_arctan_horner prec n k x",
OF ‹0 ≤ real_of_float y› F lb_arctan_horner.simps ub_arctan_horner.simps]
lemma arctan_0_1_bounds: assumes"0 ≤ real_of_float y""real_of_float y ≤ 1" shows"arctan (sqrt y) ∈ {(sqrt y * lb_arctan_horner prec (get_even n) 1 y) .. (sqrt y * ub_arctan_horner prec (get_odd n) 1 y)}" using
arctan_0_1_bounds'[OF assms, of n prec]
arctan_0_1_bounds'[OF assms, of "n + 1" prec]
arctan_0_1_bounds'[OF assms, of "n - 1" prec] by (auto simp: get_even_def get_odd_def odd_pos
simp del: ub_arctan_horner.simps lb_arctan_horner.simps)
lemma arctan_lower_bound: assumes"0 ≤ x" shows"x / (1 + x🪙2) ≤ arctan x" (is"?l x ≤ _") proof - have"?l x - arctan x ≤ ?l 0 - arctan 0" using assms by (intro DERIV_nonpos_imp_nonincreasing[where f="λx. ?l x - arctan x"])
(auto intro!: derivative_eq_intros simp: add_nonneg_eq_0_iff field_simps) thus ?thesis by simp qed
lemma arctan_divide_mono: "0 < x ==> x ≤ y ==> arctan y / y ≤ arctan x / x" by (rule DERIV_nonpos_imp_nonincreasing[where f="λx. arctan x / x"])
(auto intro!: derivative_eq_intros divide_nonpos_nonneg
simp: inverse_eq_divide arctan_lower_bound)
lemma arctan_mult_mono: "0 ≤ x ==> x ≤ y ==> x * arctan y ≤ y * arctan x" using arctan_divide_mono[of x y] by (cases "x = 0") (simp_all add: field_simps)
lemma arctan_mult_le: assumes"0 ≤ x""x ≤ y""y * z ≤ arctan y" shows"x * z ≤ arctan x" proof (cases "x = 0") case True thenshow ?thesis by simp next case False with assms have"z ≤ arctan y / y"by (simp add: field_simps) alsohave"…≤ arctan x / x"using assms ‹x ≠ 0›by (auto intro!: arctan_divide_mono) finallyshow ?thesis using assms ‹x ≠ 0›by (simp add: field_simps) qed
lemma arctan_le_mult: assumes"0 < x""x ≤ y""arctan x ≤ x * z" shows"arctan y ≤ y * z" proof - from assms have"arctan y / y ≤ arctan x / x"by (auto intro!: arctan_divide_mono) alsohave"…≤ z"using assms by (auto simp: field_simps) finallyshow ?thesis using assms by (simp add: field_simps) qed
{ fix prec n :: nat fix k :: int assume"1 < k"hence"0 ≤ k"and"0 < k"and"1 ≤ k"by auto let ?k = "rapprox_rat prec 1 k" let ?kl = "float_round_down (Suc prec) (?k * ?k)" have"1 div k = 0"using div_pos_pos_trivial[OF _ ‹1 🚫›] by auto
have"pi ≤ ub_pi n " unfolding ub_pi_def machin_pi Let_def times_float.rep_eq Float_num using lb_arctan[of 239] ub_arctan[of 5] powr_realpow[of 2 2] by (intro mult_left_mono float_plus_up_le float_plus_down_le)
(auto intro!: mult_left_mono float_round_down_le float_round_up_le diff_mono) moreoverhave"lb_pi n ≤ pi" unfolding lb_pi_def machin_pi Let_def times_float.rep_eq Float_num using lb_arctan[of 5] ub_arctan[of 239] by (intro mult_left_mono float_plus_up_le float_plus_down_le)
(auto intro!: mult_left_mono float_round_down_le float_round_up_le diff_mono) ultimatelyshow ?thesis by auto qed
lift_definition pi_float_interval::"nat ==> float interval"is"λprec. (lb_pi prec, ub_pi prec)" using pi_boundaries by (auto intro: order_trans)
lemma lower_pi_float_interval: "lower (pi_float_interval prec) = lb_pi prec" by transfer auto lemma upper_pi_float_interval: "upper (pi_float_interval prec) = ub_pi prec" by transfer auto lemma pi_float_interval: "pi ∈ set_of (real_interval (pi_float_interval prec))" using pi_boundaries by (auto simp: set_of_eq lower_pi_float_interval upper_pi_float_interval)
subsection"Compute arcus tangens in the entire domain"
function lb_arctan :: "nat ==> float ==> float"and ub_arctan :: "nat ==> float ==> float"where "lb_arctan prec x = (let ub_horner = λ x. float_round_up prec (x * ub_arctan_horner prec (get_odd (prec div 4 + 1)) 1 (float_round_down (Suc prec) (x * x))); lb_horner = λ x. float_round_down prec (x * lb_arctan_horner prec (get_even (prec div 4 + 1)) 1 (float_round_up (Suc prec) (x * x))) in if x < 0 then - ub_arctan prec (-x) else if x ≤ Float 1 (- 1) then lb_horner x else if x ≤ Float 1 1 then Float 1 1 * lb_horner (float_divl prec x (float_plus_up prec 1 (ub_sqrt prec (float_plus_up prec 1 (float_round_up prec (x * x)))))) else let inv = float_divr prec 1 x in if inv > 1 then 0 else float_plus_down prec (lb_pi prec * Float 1 (- 1)) ( - ub_horner inv))"
| "ub_arctan prec x = (let lb_horner = λ x. float_round_down prec (x * lb_arctan_horner prec (get_even (prec div 4 + 1)) 1 (float_round_up (Suc prec) (x * x))) ; ub_horner = λ x. float_round_up prec (x * ub_arctan_horner prec (get_odd (prec div 4 + 1)) 1 (float_round_down (Suc prec) (x * x))) in if x < 0 then - lb_arctan prec (-x) else if x ≤ Float 1 (- 1) then ub_horner x else if x ≤ Float 1 1 then let y = float_divr prec x (float_plus_down (Suc prec) 1 (lb_sqrt prec (float_plus_down prec 1 (float_round_down prec (x * x))))) in if y > 1 then ub_pi prec * Float 1 (- 1) else Float 1 1 * ub_horner y else float_plus_up prec (ub_pi prec * Float 1 (- 1)) ( - lb_horner (float_divl prec 1 x)))" by pat_completeness auto termination by (relation "measure (λ v. let (prec, x) = case_sum id id v in (if x < 0 then 1 else 0))", auto)
show ?thesis proof (cases "x ≤ Float 1 (- 1)") case True hence"real_of_float x ≤ 1"by auto show ?thesis unfolding ub_arctan.simps Let_def if_not_P[OF ‹¬ x 🚫›] if_P[OF True] using arctan_0_1_bounds_round[OF ‹0 ≤ real_of_float x›‹real_of_float x ≤ 1›] by (auto intro!: float_round_up_le) next case False hence"0 < real_of_float x"by auto let ?R = "1 + sqrt (1 + real_of_float x * real_of_float x)" let ?sxx = "float_plus_down prec 1 (float_round_down prec (x * x))" let ?fR = "float_plus_down (Suc prec) 1 (lb_sqrt prec ?sxx)" let ?DIV = "float_divr prec x ?fR"
have sqr_ge0: "0 ≤ 1 + real_of_float x * real_of_float x" using sum_power2_ge_zero[of 1 "real_of_float x", unfolded numeral_2_eq_2] by auto hence"0 ≤ real_of_float (1 + x*x)"by auto
have"lb_sqrt prec ?sxx ≤ sqrt ?sxx" using bnds_sqrt'[of ?sxx] by auto alsohave"…≤ sqrt (1 + x*x)" by (auto simp: float_plus_down.rep_eq plus_down_def float_round_down.rep_eq truncate_down_le) finallyhave"lb_sqrt prec ?sxx ≤ sqrt (1 + x*x)" . hence"?fR ≤ ?R" by (auto simp: float_plus_down.rep_eq plus_down_def truncate_down_le) have"0 < real_of_float ?fR" by (auto simp: float_plus_down.rep_eq plus_down_def float_round_down.rep_eq
intro!: truncate_down_ge1 lb_sqrt_lower_bound order_less_le_trans[OF zero_less_one]
truncate_down_nonneg add_nonneg_nonneg) have monotone: "x / ?R ≤ (float_divr prec x ?fR)" proof - from divide_left_mono[OF ‹?fR ≤ ?R›‹0 ≤ real_of_float x› mult_pos_pos[OF divisor_gt0 ‹0 🚫 ?fR›]] have"x / ?R ≤ x / ?fR" . alsohave"…≤ ?DIV"by (rule float_divr) finallyshow ?thesis . qed
show ?thesis proof (cases "x ≤ Float 1 1") case True show ?thesis proof (cases "?DIV > 1") case True have"pi / 2 ≤ ub_pi prec * Float 1 (- 1)" unfolding Float_num times_divide_eq_right mult_1_left using pi_boundaries by auto from order_less_le_trans[OF arctan_ubound this, THEN less_imp_le] show ?thesis unfolding ub_arctan.simps Let_def if_not_P[OF ‹¬ x 🚫›]
if_not_P[OF ‹¬ x ≤ Float 1 (- 1)›] if_P[OF ‹x ≤ Float 1 1›] if_P[OF True] . next case False hence"real_of_float ?DIV ≤ 1"by auto
have"0 ≤ x / ?R" using‹0 ≤ real_of_float x›‹0 🚫R›unfolding zero_le_divide_iff by auto hence"0 ≤ real_of_float ?DIV" using monotone by (rule order_trans)
have"arctan x = 2 * arctan (x / ?R)" using arctan_half unfolding numeral_2_eq_2 power_Suc2 power_0 mult_1_left . alsohave"…≤ 2 * arctan (?DIV)" using arctan_monotone'[OF monotone] by (auto intro!: mult_left_mono) alsohave"…≤ (Float 1 1 * ?ub_horner ?DIV)"unfolding Float_num using arctan_0_1_bounds_round[OF ‹0 ≤ real_of_float ?DIV›‹real_of_float ?DIV ≤ 1›] by (auto intro!: float_round_up_le) finallyshow ?thesis unfolding ub_arctan.simps Let_def if_not_P[OF ‹¬ x 🚫›]
if_not_P[OF ‹¬ x ≤ Float 1 (- 1)›] if_P[OF ‹x ≤ Float 1 1›] if_not_P[OF False] . qed next case False hence"2 < real_of_float x"by auto hence"1 ≤ real_of_float x"by auto hence"0 < real_of_float x"by auto hence"0 < x"by auto
let"?invx" = "float_divl prec 1 x" have"0 ≤ arctan x" using arctan_monotone'[OF ‹0 ≤ real_of_float x›] and arctan_tan[of 0, unfolded tan_zero] by auto
lemma lb_arctan: "arctan (real_of_float x) ≤ y ==> real_of_float (lb_arctan prec x) ≤ y" and ub_arctan: "y ≤ arctan x ==> y ≤ ub_arctan prec x" for x::float and y::real using arctan_boundaries[of x prec] by auto
lemma lower_arctan_float_interval: "lower (arctan_float_interval p x) = lb_arctan p (lower x)" by transfer auto lemma upper_arctan_float_interval: "upper (arctan_float_interval p x) = ub_arctan p (upper x)" by transfer auto
lemma arctan_float_intervalI: "arctan x ∈🪙r arctan_float_interval p X"if"x ∈🪙r X" using arctan_float_interval[of X p] that by auto
section"Sinus and Cosinus"
subsection"Compute the cosinus and sinus series"
fun ub_sin_cos_aux :: "nat ==> nat ==> nat ==> nat ==> float ==> float" and lb_sin_cos_aux :: "nat ==> nat ==> nat ==> nat ==> float ==> float"where "ub_sin_cos_aux prec 0 i k x = 0"
| "ub_sin_cos_aux prec (Suc n) i k x = float_plus_up prec (rapprox_rat prec 1 k) (- float_round_down prec (x * (lb_sin_cos_aux prec n (i + 2) (k * i * (i + 1)) x)))"
| "lb_sin_cos_aux prec 0 i k x = 0"
| "lb_sin_cos_aux prec (Suc n) i k x = float_plus_down prec (lapprox_rat prec 1 k) (- float_round_up prec (x * (ub_sin_cos_aux prec n (i + 2) (k * i * (i + 1)) x)))"
lemma cos_aux: shows"(lb_sin_cos_aux prec n 1 1 (x * x)) ≤ (∑ i=0.. (is"?lb") and"(∑ i=0..≤ (ub_sin_cos_aux prec n 1 1 (x * x))" (is"?ub") proof - have"0 ≤ real_of_float (x * x)"by auto let"?f n" = "fact (2 * n) :: nat" have f_eq: "?f (Suc n) = ?f n * ((λi. i + 2) ^^ n) 1 * (((λi. i + 2) ^^ n) 1 + 1)"for n proof - have"∧m. ((λi. i + 2) ^^ n) m = m + 2 * n"by (induct n) auto thenshow ?thesis by auto qed from horner_bounds[where lb="lb_sin_cos_aux prec"and ub="ub_sin_cos_aux prec"and j'=0,
OF ‹0 ≤ real_of_float (x * x)› f_eq lb_sin_cos_aux.simps ub_sin_cos_aux.simps] show ?lb and ?ub by (auto simp add: power_mult power2_eq_square[of "real_of_float x"]) qed
lemma lb_sin_cos_aux_zero_le_one: "lb_sin_cos_aux prec n i j 0 ≤ 1" by (cases j n rule: nat.exhaust[case_product nat.exhaust])
(auto intro!: float_plus_down_le order_trans[OF lapprox_rat])
lemma one_le_ub_sin_cos_aux: "odd n ==> 1 ≤ ub_sin_cos_aux prec n i (Suc 0) 0" by (cases n) (auto intro!: float_plus_up_le order_trans[OF _ rapprox_rat])
lemma cos_boundaries: assumes"0 ≤ real_of_float x"and"x ≤ pi / 2" shows"cos x ∈ {(lb_sin_cos_aux prec (get_even n) 1 1 (x * x)) .. (ub_sin_cos_aux prec (get_odd n) 1 1 (x * x))}" proof (cases "real_of_float x = 0") case False hence"real_of_float x ≠ 0"by auto hence"0 < x"and"0 < real_of_float x" using‹0 ≤ real_of_float x›by auto have"0 < x * x" using‹0 🚫›by simp
have morph_to_if_power: "(∑ i=0.. (∑ i = 0 ..< 2 * n. (if even(i) then ((- 1) ^ (i div 2))/((fact i)) else 0) * x ^ i)"
(is"?sum = ?ifsum") for x n proof - have"?sum = ?sum + (∑ j = 0 ..< n. 0)"by auto alsohave"… = (∑ j = 0 ..< n. (- 1) ^ ((2 * j) div 2) / ((fact (2 * j))) * x ^(2 * j)) + (∑ j = 0 ..< n. 0)"by auto alsohave"… = (∑ i = 0 ..< 2 * n. if even i then (- 1) ^ (i div 2) / ((fact i)) * x ^ i else 0)" unfolding sum_split_even_odd atLeast0LessThan .. alsohave"… = (∑ i = 0 ..< 2 * n. (if even i then (- 1) ^ (i div 2) / ((fact i)) else 0) * x ^ i)" by (rule sum.cong) auto finallyshow ?thesis . qed
{ fix n :: nat assume"0 < n" hence"0 < 2 * n"by auto obtain t where"0 < t"and"t < real_of_float x"and
cos_eq: "cos x = (∑ i = 0 ..< 2 * n. (if even(i) then ((- 1) ^ (i div 2))/((fact i)) else 0) * (real_of_float x) ^ i) + (cos (t + 1/2 * (2 * n) * pi) / (fact (2*n))) * (real_of_float x)^(2*n)"
(is"_ = ?SUM + ?rest / ?fact * ?pow") using Maclaurin_cos_expansion2[OF ‹0 🚫 x›‹0 🚫 * n›] unfolding cos_coeff_def atLeast0LessThan by auto
have"cos t * (- 1) ^ n = cos t * cos (n * pi) + sin t * sin (n * pi)"by auto alsohave"… = cos (t + n * pi)"by (simp add: cos_add) alsohave"… = ?rest"by auto finallyhave"cos t * (- 1) ^ n = ?rest" . moreover have"t ≤ pi / 2"using‹t 🚫 x›and‹x ≤ pi / 2›by auto hence"0 ≤ cos t"using‹0 🚫›and cos_ge_zero by auto ultimatelyhave even: "even n ==> 0 ≤ ?rest"and odd: "odd n ==> 0 ≤ - ?rest "by auto
have"0 < ?fact"by auto have"0 < ?pow"using‹0 🚫 x›by auto
{ assume"even n" have"(lb_sin_cos_aux prec n 1 1 (x * x)) ≤ ?SUM" unfolding morph_to_if_power[symmetric] using cos_aux by auto alsohave"…≤ cos x" proof - from even[OF ‹even n›] ‹0 🚫fact›‹0 🚫pow› have"0 ≤ (?rest / ?fact) * ?pow"by simp thus ?thesis unfolding cos_eq by auto qed finallyhave"(lb_sin_cos_aux prec n 1 1 (x * x)) ≤ cos x" .
} note lb = this
{ assume"odd n" have"cos x ≤ ?SUM" proof - from‹0 🚫fact›and‹0 🚫pow›and odd[OF ‹odd n›] have"0 ≤ (- ?rest) / ?fact * ?pow" by (metis mult_nonneg_nonneg divide_nonneg_pos less_imp_le) thus ?thesis unfolding cos_eq by auto qed alsohave"…≤ (ub_sin_cos_aux prec n 1 1 (x * x))" unfolding morph_to_if_power[symmetric] using cos_aux by auto finallyhave"cos x ≤ (ub_sin_cos_aux prec n 1 1 (x * x))" .
} note ub = this and lb
} note ub = this(1) and lb = this(2)
have"cos x ≤ (ub_sin_cos_aux prec (get_odd n) 1 1 (x * x))" using ub[OF odd_pos[OF get_odd] get_odd] . moreoverhave"(lb_sin_cos_aux prec (get_even n) 1 1 (x * x)) ≤ cos x" proof (cases "0 < get_even n") case True show ?thesis using lb[OF True get_even] . next case False hence"get_even n = 0"by auto have"- (pi / 2) ≤ x" by (rule order_trans[OF _ ‹0 🚫 x›[THEN less_imp_le]]) auto with‹x ≤ pi / 2›show ?thesis unfolding‹get_even n = 0› lb_sin_cos_aux.simps minus_float.rep_eq zero_float.rep_eq using cos_ge_zero by auto qed ultimatelyshow ?thesis by auto next case True hence"x = 0" by (simp add: real_of_float_eq) thus ?thesis using lb_sin_cos_aux_zero_le_one one_le_ub_sin_cos_aux by simp qed
lemma sin_aux: assumes"0 ≤ real_of_float x" shows"(x * lb_sin_cos_aux prec n 2 1 (x * x)) ≤ (∑ i=0.. (is"?lb") and"(∑ i=0..≤ (x * ub_sin_cos_aux prec n 2 1 (x * x))" (is"?ub") proof - have"0 ≤ real_of_float (x * x)"by auto let"?f n" = "fact (2 * n + 1) :: nat" have f_eq: "?f (Suc n) = ?f n * ((λi. i + 2) ^^ n) 2 * (((λi. i + 2) ^^ n) 2 + 1)"for n proof - have F: "∧m. ((λi. i + 2) ^^ n) m = m + 2 * n"by (induct n) auto show ?thesis unfolding F by auto qed from horner_bounds[where lb="lb_sin_cos_aux prec"and ub="ub_sin_cos_aux prec"and j'=0,
OF ‹0 ≤ real_of_float (x * x)› f_eq lb_sin_cos_aux.simps ub_sin_cos_aux.simps] show"?lb"and"?ub"using‹0 ≤ real_of_float x› apply (simp_all only: power_add power_one_right mult.assoc[symmetric] sum_distrib_right[symmetric]) apply (simp_all only: mult.commute[where 'a=real] of_nat_fact) apply (auto intro!: mult_left_mono simp add: power_mult power2_eq_square[of "real_of_float x"]) done qed
lemma sin_boundaries: assumes"0 ≤ real_of_float x" and"x ≤ pi / 2" shows"sin x ∈ {(x * lb_sin_cos_aux prec (get_even n) 2 1 (x * x)) .. (x * ub_sin_cos_aux prec (get_odd n) 2 1 (x * x))}" proof (cases "real_of_float x = 0") case False hence"real_of_float x ≠ 0"by auto hence"0 < x"and"0 < real_of_float x" using‹0 ≤ real_of_float x›by auto have"0 < x * x" using‹0 🚫›by simp
have sum_morph: "(∑j = 0 ..< n. (- 1) ^ (((2 * j + 1) - Suc 0) div 2) / ((fact (2 * j + 1))) * x ^(2 * j + 1)) = (∑ i = 0 ..< 2 * n. (if even(i) then 0 else ((- 1) ^ ((i - Suc 0) div 2))/((fact i))) * x ^ i)"
(is"?SUM = _") for x :: real and n proof - have pow: "!!i. x ^ (2 * i + 1) = x * x ^ (2 * i)" by auto have"?SUM = (∑ j = 0 ..< n. 0) + ?SUM" by auto alsohave"… = (∑ i = 0 ..< 2 * n. if even i then 0 else (- 1) ^ ((i - Suc 0) div 2) / ((fact i)) * x ^ i)" unfolding sum_split_even_odd atLeast0LessThan .. alsohave"… = (∑ i = 0 ..< 2 * n. (if even i then 0 else (- 1) ^ ((i - Suc 0) div 2) / ((fact i))) * x ^ i)" by (rule sum.cong) auto finallyshow ?thesis . qed
{ fix n :: nat assume"0 < n" hence"0 < 2 * n + 1"by auto obtain t where"0 < t"and"t < real_of_float x"and
sin_eq: "sin x = (∑ i = 0 ..< 2 * n + 1. (if even(i) then 0 else ((- 1) ^ ((i - Suc 0) div 2))/((fact i))) * (real_of_float x) ^ i) + (sin (t + 1/2 * (2 * n + 1) * pi) / (fact (2*n + 1))) * (real_of_float x)^(2*n + 1)"
(is"_ = ?SUM + ?rest / ?fact * ?pow") using Maclaurin_sin_expansion3[OF ‹0 🚫 * n + 1›‹0 🚫 x›] unfolding sin_coeff_def atLeast0LessThan by auto
have"?rest = cos t * (- 1) ^ n" unfolding sin_add cos_add of_nat_add distrib_right distrib_left by auto moreover have"t ≤ pi / 2" using‹t 🚫 x›and‹x ≤ pi / 2›by auto hence"0 ≤ cos t" using‹0 🚫›and cos_ge_zero by auto ultimatelyhave even: "even n ==> 0 ≤ ?rest"and odd: "odd n ==> 0 ≤ - ?rest" by auto
{ assume"even n" have"(x * lb_sin_cos_aux prec n 2 1 (x * x)) ≤ (∑ i = 0 ..< 2 * n. (if even(i) then 0 else ((- 1) ^ ((i - Suc 0) div 2))/((fact i))) * (real_of_float x) ^ i)" using sin_aux[OF ‹0 ≤ real_of_float x›] unfolding sum_morph[symmetric] by auto alsohave"…≤ ?SUM"by auto alsohave"…≤ sin x" proof - from even[OF ‹even n›] ‹0 🚫fact›‹0 🚫pow› have"0 ≤ (?rest / ?fact) * ?pow"by simp thus ?thesis unfolding sin_eq by auto qed finallyhave"(x * lb_sin_cos_aux prec n 2 1 (x * x)) ≤ sin x" .
} note lb = this
{ assume"odd n" have"sin x ≤ ?SUM" proof - from‹0 🚫fact›and‹0 🚫pow›and odd[OF ‹odd n›] have"0 ≤ (- ?rest) / ?fact * ?pow" by (metis mult_nonneg_nonneg divide_nonneg_pos less_imp_le) thus ?thesis unfolding sin_eq by auto qed alsohave"…≤ (∑ i = 0 ..< 2 * n. (if even(i) then 0 else ((- 1) ^ ((i - Suc 0) div 2))/((fact i))) * (real_of_float x) ^ i)" by auto alsohave"…≤ (x * ub_sin_cos_aux prec n 2 1 (x * x))" using sin_aux[OF ‹0 ≤ real_of_float x›] unfolding sum_morph[symmetric] by auto finallyhave"sin x ≤ (x * ub_sin_cos_aux prec n 2 1 (x * x))" .
} note ub = this and lb
} note ub = this(1) and lb = this(2)
have"sin x ≤ (x * ub_sin_cos_aux prec (get_odd n) 2 1 (x * x))" using ub[OF odd_pos[OF get_odd] get_odd] . moreoverhave"(x * lb_sin_cos_aux prec (get_even n) 2 1 (x * x)) ≤ sin x" proof (cases "0 < get_even n") case True show ?thesis using lb[OF True get_even] . next case False hence"get_even n = 0"by auto with‹x ≤ pi / 2›‹0 ≤ real_of_float x› show ?thesis unfolding‹get_even n = 0› ub_sin_cos_aux.simps minus_float.rep_eq using sin_ge_zero by auto qed ultimatelyshow ?thesis by auto next case True show ?thesis proof (cases "n = 0") case True thus ?thesis unfolding‹n = 0› get_even_def get_odd_def using‹real_of_float x = 0› lapprox_rat[where x="-1"and y=1] by auto next case False with not0_implies_Suc obtain m where"n = Suc m"by blast thus ?thesis unfolding‹n = Suc m› get_even_def get_odd_def using‹real_of_float x = 0› rapprox_rat[where x=1 and y=1] lapprox_rat[where x=1 and y=1] by (cases "even (Suc m)") auto qed qed
subsection"Compute the cosinus in the entire domain"
definition lb_cos :: "nat ==> float ==> float"where "lb_cos prec x = (let horner = λ x. lb_sin_cos_aux prec (get_even (prec div 4 + 1)) 1 1 (x * x) ; half = λ x. if x < 0 then - 1 else float_plus_down prec (Float 1 1 * x * x) (- 1) in if x < Float 1 (- 1) then horner x else if x < 1 then half (horner (x * Float 1 (- 1))) else half (half (horner (x * Float 1 (- 2)))))"
definition ub_cos :: "nat ==> float ==> float"where "ub_cos prec x = (let horner = λ x. ub_sin_cos_aux prec (get_odd (prec div 4 + 1)) 1 1 (x * x) ; half = λ x. float_plus_up prec (Float 1 1 * x * x) (- 1) in if x < Float 1 (- 1) then horner x else if x < 1 then half (horner (x * Float 1 (- 1))) else half (half (horner (x * Float 1 (- 2)))))"
lemma lb_cos: assumes"0 ≤ real_of_float x"and"x ≤ pi" shows"cos x ∈ {(lb_cos prec x) .. (ub_cos prec x)}" (is"?cos x ∈ {(?lb x) .. (?ub x) }") proof - have x_half[symmetric]: "cos x = 2 * cos (x / 2) * cos (x / 2) - 1"for x :: real proof - have"cos x = cos (x / 2 + x / 2)" by auto alsohave"… = cos (x / 2) * cos (x / 2) + sin (x / 2) * sin (x / 2) - sin (x / 2) * sin (x / 2) + cos (x / 2) * cos (x / 2) - 1" unfolding cos_add by auto alsohave"… = 2 * cos (x / 2) * cos (x / 2) - 1" by algebra finallyshow ?thesis . qed
have"¬ x < 0"using‹0 ≤ real_of_float x›by auto let"?ub_horner x" = "ub_sin_cos_aux prec (get_odd (prec div 4 + 1)) 1 1 (x * x)" let"?lb_horner x" = "lb_sin_cos_aux prec (get_even (prec div 4 + 1)) 1 1 (x * x)" let"?ub_half x" = "float_plus_up prec (Float 1 1 * x * x) (- 1)" let"?lb_half x" = "if x < 0 then - 1 else float_plus_down prec (Float 1 1 * x * x) (- 1)"
show ?thesis proof (cases "x < Float 1 (- 1)") case True hence"x ≤ pi / 2" using pi_ge_two by auto show ?thesis unfolding lb_cos_def[where x=x] ub_cos_def[where x=x]
if_not_P[OF ‹¬ x 🚫›] if_P[OF ‹x 🚫 1 (- 1)›] Let_def using cos_boundaries[OF ‹0 ≤ real_of_float x›‹x ≤ pi / 2›] . next case False
{ fix y x :: float let ?x2 = "(x * Float 1 (- 1))" assume"y ≤ cos ?x2"and"-pi ≤ x"and"x ≤ pi" hence"- (pi / 2) ≤ ?x2"and"?x2 ≤ pi / 2" using pi_ge_two unfolding Float_num by auto hence"0 ≤ cos ?x2" by (rule cos_ge_zero)
have"(?lb_half y) ≤ cos x" proof (cases "y < 0") case True show ?thesis using cos_ge_minus_one unfolding if_P[OF True] by auto next case False hence"0 ≤ real_of_float y"by auto from mult_mono[OF ‹y ≤ cos ?x2›‹y ≤ cos ?x2›‹0 ≤ cos ?x2› this] have"real_of_float y * real_of_float y ≤ cos ?x2 * cos ?x2" . hence"2 * real_of_float y * real_of_float y ≤ 2 * cos ?x2 * cos ?x2" by auto hence"2 * real_of_float y * real_of_float y - 1 ≤ 2 * cos (x / 2) * cos (x / 2) - 1" unfolding Float_num by auto thus ?thesis unfolding if_not_P[OF False] x_half Float_num by (auto intro!: float_plus_down_le) qed
} note lb_half = this
{ fix y x :: float let ?x2 = "(x * Float 1 (- 1))" assume ub: "cos ?x2 ≤ y"and"- pi ≤ x"and"x ≤ pi" hence"- (pi / 2) ≤ ?x2"and"?x2 ≤ pi / 2" using pi_ge_two unfolding Float_num by auto hence"0 ≤ cos ?x2"by (rule cos_ge_zero)
have"cos x ≤ (?ub_half y)" proof - have"0 ≤ real_of_float y" using‹0 ≤ cos ?x2› ub by (rule order_trans) from mult_mono[OF ub ub this ‹0 ≤ cos ?x2›] have"cos ?x2 * cos ?x2 ≤ real_of_float y * real_of_float y" . hence"2 * cos ?x2 * cos ?x2 ≤ 2 * real_of_float y * real_of_float y" by auto hence"2 * cos (x / 2) * cos (x / 2) - 1 ≤ 2 * real_of_float y * real_of_float y - 1" unfolding Float_num by auto thus ?thesis unfolding x_half Float_num by (auto intro!: float_plus_up_le) qed
} note ub_half = this
have"-pi ≤ x" using pi_ge_zero[THEN le_imp_neg_le, unfolded minus_zero] ‹0 ≤ real_of_float x› by (rule order_trans)
show ?thesis proof (cases "x < 1") case True hence"real_of_float x ≤ 1"by auto have"0 ≤ real_of_float ?x2"and"?x2 ≤ pi / 2" using pi_ge_two ‹0 ≤ real_of_float x›using assms by auto from cos_boundaries[OF this] have lb: "(?lb_horner ?x2) ≤ ?cos ?x2"and ub: "?cos ?x2 ≤ (?ub_horner ?x2)" by auto
have"(?lb x) ≤ ?cos x" proof - from lb_half[OF lb ‹-pi ≤ x›‹x ≤ pi›] show ?thesis unfolding lb_cos_def[where x=x] Let_def using‹¬ x 🚫›‹¬ x 🚫 1 (- 1)›‹x 🚫›by auto qed moreoverhave"?cos x ≤ (?ub x)" proof - from ub_half[OF ub ‹-pi ≤ x›‹x ≤ pi›] show ?thesis unfolding ub_cos_def[where x=x] Let_def using‹¬ x 🚫›‹¬ x 🚫 1 (- 1)›‹x 🚫›by auto qed ultimatelyshow ?thesis by auto next case False have"0 ≤ real_of_float ?x4"and"?x4 ≤ pi / 2" using pi_ge_two ‹0 ≤ real_of_float x›‹x ≤ pi›unfolding Float_num by auto from cos_boundaries[OF this] have lb: "(?lb_horner ?x4) ≤ ?cos ?x4"and ub: "?cos ?x4 ≤ (?ub_horner ?x4)" by auto
have eq_4: "?x2 * Float 1 (- 1) = x * Float 1 (- 2)" by (auto simp: real_of_float_eq)
have"(?lb x) ≤ ?cos x" proof - have"-pi ≤ ?x2"and"?x2 ≤ pi" using pi_ge_two ‹0 ≤ real_of_float x›‹x ≤ pi›by auto from lb_half[OF lb_half[OF lb this] ‹-pi ≤ x›‹x ≤ pi›, unfolded eq_4] show ?thesis unfolding lb_cos_def[where x=x] if_not_P[OF ‹¬ x 🚫›]
if_not_P[OF ‹¬ x 🚫 1 (- 1)›] if_not_P[OF ‹¬ x 🚫›] Let_def . qed moreoverhave"?cos x ≤ (?ub x)" proof - have"-pi ≤ ?x2"and"?x2 ≤ pi" using pi_ge_two ‹0 ≤ real_of_float x›‹ x ≤ pi›by auto from ub_half[OF ub_half[OF ub this] ‹-pi ≤ x›‹x ≤ pi›, unfolded eq_4] show ?thesis unfolding ub_cos_def[where x=x] if_not_P[OF ‹¬ x 🚫›]
if_not_P[OF ‹¬ x 🚫 1 (- 1)›] if_not_P[OF ‹¬ x 🚫›] Let_def . qed ultimatelyshow ?thesis by auto qed qed qed
lemma lb_cos_minus: assumes"-pi ≤ x" and"real_of_float x ≤ 0" shows"cos (real_of_float(-x)) ∈ {(lb_cos prec (-x)) .. (ub_cos prec (-x))}" proof - have"0 ≤ real_of_float (-x)"and"(-x) ≤ pi" using‹-pi ≤ x›‹real_of_float x ≤ 0›by auto from lb_cos[OF this] show ?thesis . qed
definition bnds_cos :: "nat ==> float ==> float ==> float * float"where "bnds_cos prec lx ux = (let lpi = float_round_down prec (lb_pi prec) ; upi = float_round_up prec (ub_pi prec) ; k = floor_fl (float_divr prec (lx + lpi) (2 * lpi)) ; lx = float_plus_down prec lx (- k * 2 * (if k < 0 then lpi else upi)) ; ux = float_plus_up prec ux (- k * 2 * (if k < 0 then upi else lpi)) in if - lpi ≤ lx ∧ ux ≤ 0 then (lb_cos prec (-lx), ub_cos prec (-ux)) else if 0 ≤ lx ∧ ux ≤ lpi then (lb_cos prec ux, ub_cos prec lx) else if - lpi ≤ lx ∧ ux ≤ lpi then (min (lb_cos prec (-lx)) (lb_cos prec ux), Float 1 0) else if 0 ≤ lx ∧ ux ≤ 2 * lpi then (Float (- 1) 0, max (ub_cos prec lx) (ub_cos prec (- (ux - 2 * lpi)))) else if -2 * lpi ≤ lx ∧ ux ≤ 0 then (Float (- 1) 0, max (ub_cos prec (lx + 2 * lpi)) (ub_cos prec (-ux))) else (Float (- 1) 0, Float 1 0))"
lemma floor_int: obtains k :: int where"real_of_int k = (floor_fl f)" by (simp add: floor_fl_def)
lemma cos_periodic_nat[simp]: fixes n :: nat shows"cos (x + n * (2 * pi)) = cos x" proof (induct n arbitrary: x) case 0 thenshow ?caseby simp next case (Suc n) have split_pi_off: "x + (Suc n) * (2 * pi) = (x + n * (2 * pi)) + 2 * pi" unfolding Suc_eq_plus1 of_nat_add of_int_1 distrib_right by auto show ?case unfolding split_pi_off using Suc by auto qed
lemma cos_periodic_int[simp]: fixes i :: int shows"cos (x + i * (2 * pi)) = cos x" proof (cases "0 ≤ i") case True hence i_nat: "real_of_int i = nat i"by auto show ?thesis unfolding i_nat by auto next case False hence i_nat: "i = - real (nat (-i))"by auto have"cos x = cos (x + i * (2 * pi) - i * (2 * pi))" by auto alsohave"… = cos (x + i * (2 * pi))" unfolding i_nat mult_minus_left diff_minus_eq_add by (rule cos_periodic_nat) finallyshow ?thesis by auto qed
lemma bnds_cos: "∀(x::real) lx ux. (l, u) = bnds_cos prec lx ux ∧ x ∈ {lx .. ux} ⟶ l ≤ cos x ∧ cos x ≤ u" proof (rule allI | rule impI | erule conjE)+ fix x :: real fix lx ux assume bnds: "(l, u) = bnds_cos prec lx ux"and x: "x ∈ {lx .. ux}"
let ?lpi = "float_round_down prec (lb_pi prec)" let ?upi = "float_round_up prec (ub_pi prec)" let ?k = "floor_fl (float_divr prec (lx + ?lpi) (2 * ?lpi))" let ?lx2 = "(- ?k * 2 * (if ?k < 0 then ?lpi else ?upi))" let ?ux2 = "(- ?k * 2 * (if ?k < 0 then ?upi else ?lpi))" let ?lx = "float_plus_down prec lx ?lx2" let ?ux = "float_plus_up prec ux ?ux2"
obtain k :: int where k: "k = real_of_float ?k" by (rule floor_int)
have upi: "pi ≤ ?upi"and lpi: "?lpi ≤ pi" using float_round_up[of "ub_pi prec" prec] pi_boundaries[of prec]
float_round_down[of prec "lb_pi prec"] by auto hence"lx + ?lx2 ≤ x - k * (2 * pi) ∧ x - k * (2 * pi) ≤ ux + ?ux2" using x by (cases "k = 0")
(auto intro!: add_mono
simp add: k [symmetric] uminus_add_conv_diff [symmetric]
simp del: uminus_add_conv_diff) hence"?lx ≤ x - k * (2 * pi) ∧ x - k * (2 * pi) ≤ ?ux" by (auto intro!: float_plus_down_le float_plus_up_le) note lx = this[THEN conjunct1] and ux = this[THEN conjunct2] hence lx_less_ux: "?lx ≤ real_of_float ?ux"by (rule order_trans)
{ assume"- ?lpi ≤ ?lx"and x_le_0: "x - k * (2 * pi) ≤ 0" with lpi[THEN le_imp_neg_le] lx have pi_lx: "- pi ≤ ?lx"and lx_0: "real_of_float ?lx ≤ 0" by simp_all
have"(lb_cos prec (- ?lx)) ≤ cos (real_of_float (- ?lx))" using lb_cos_minus[OF pi_lx lx_0] by simp alsohave"…≤ cos (x + (-k) * (2 * pi))" using cos_monotone_minus_pi_0'[OF pi_lx lx x_le_0] by (simp only: uminus_float.rep_eq of_int_minus
cos_minus mult_minus_left) simp finallyhave"(lb_cos prec (- ?lx)) ≤ cos x" unfolding cos_periodic_int . } note negative_lx = this
{ assume"0 ≤ ?lx"and pi_x: "x - k * (2 * pi) ≤ pi" with lx have pi_lx: "?lx ≤ pi"and lx_0: "0 ≤ real_of_float ?lx" by auto
have"cos (x + (-k) * (2 * pi)) ≤ cos ?lx" using cos_monotone_0_pi_le[OF lx_0 lx pi_x] by (simp only: of_int_minus
cos_minus mult_minus_left) simp alsohave"…≤ (ub_cos prec ?lx)" using lb_cos[OF lx_0 pi_lx] by simp finallyhave"cos x ≤ (ub_cos prec ?lx)" unfolding cos_periodic_int . } note positive_lx = this
{ assume pi_x: "- pi ≤ x - k * (2 * pi)"and"?ux ≤ 0" with ux have pi_ux: "- pi ≤ ?ux"and ux_0: "real_of_float ?ux ≤ 0" by simp_all
have"cos (x + (-k) * (2 * pi)) ≤ cos (real_of_float (- ?ux))" using cos_monotone_minus_pi_0'[OF pi_x ux ux_0] by (simp only: uminus_float.rep_eq of_int_minus
cos_minus mult_minus_left) simp alsohave"…≤ (ub_cos prec (- ?ux))" using lb_cos_minus[OF pi_ux ux_0, of prec] by simp finallyhave"cos x ≤ (ub_cos prec (- ?ux))" unfolding cos_periodic_int . } note negative_ux = this
{ assume"?ux ≤ ?lpi"and x_ge_0: "0 ≤ x - k * (2 * pi)" with lpi ux have pi_ux: "?ux ≤ pi"and ux_0: "0 ≤ real_of_float ?ux" by simp_all
have"(lb_cos prec ?ux) ≤ cos ?ux" using lb_cos[OF ux_0 pi_ux] by simp alsohave"…≤ cos (x + (-k) * (2 * pi))" using cos_monotone_0_pi_le[OF x_ge_0 ux pi_ux] by (simp only: of_int_minus
cos_minus mult_minus_left) simp finallyhave"(lb_cos prec ?ux) ≤ cos x" unfolding cos_periodic_int . } note positive_ux = this
show"l ≤ cos x ∧ cos x ≤ u" proof (cases "- ?lpi ≤ ?lx ∧ ?ux ≤ 0") case True with bnds have l: "l = lb_cos prec (-?lx)"and u: "u = ub_cos prec (-?ux)" by (auto simp add: bnds_cos_def Let_def) from True lpi[THEN le_imp_neg_le] lx ux have"- pi ≤ x - k * (2 * pi)"and"x - k * (2 * pi) ≤ 0" by auto with True negative_ux negative_lx show ?thesis unfolding l u by simp next case 1: False show ?thesis proof (cases "0 ≤ ?lx ∧ ?ux ≤ ?lpi") case True with bnds 1 have l: "l = lb_cos prec ?ux" and u: "u = ub_cos prec ?lx" by (auto simp add: bnds_cos_def Let_def) from True lpi lx ux have"0 ≤ x - k * (2 * pi)"and"x - k * (2 * pi) ≤ pi" by auto with True positive_ux positive_lx show ?thesis unfolding l u by simp next case 2: False show ?thesis proof (cases "- ?lpi ≤ ?lx ∧ ?ux ≤ ?lpi") case Cond: True with bnds 1 2 have l: "l = min (lb_cos prec (-?lx)) (lb_cos prec ?ux)" and u: "u = Float 1 0" by (auto simp add: bnds_cos_def Let_def) show ?thesis unfolding u l using negative_lx positive_ux Cond by (cases "x - k * (2 * pi) < 0") (auto simp add: real_of_float_min) next case 3: False show ?thesis proof (cases "0 ≤ ?lx ∧ ?ux ≤ 2 * ?lpi") case Cond: True with bnds 1 2 3 have l: "l = Float (- 1) 0" and u: "u = max (ub_cos prec ?lx) (ub_cos prec (- (?ux - 2 * ?lpi)))" by (auto simp add: bnds_cos_def Let_def)
have"cos x ≤ real_of_float u" proof (cases "x - k * (2 * pi) < pi") case True hence"x - k * (2 * pi) ≤ pi"by simp from positive_lx[OF Cond[THEN conjunct1] this] show ?thesis unfolding u by (simp add: real_of_float_max) next case False hence"pi ≤ x - k * (2 * pi)"by simp hence pi_x: "- pi ≤ x - k * (2 * pi) - 2 * pi"by simp
have"?ux ≤ 2 * pi" using Cond lpi by auto hence"x - k * (2 * pi) - 2 * pi ≤ 0" using ux by simp
have ux_0: "real_of_float (?ux - 2 * ?lpi) ≤ 0" using Cond by auto
from 2 and Cond have"¬ ?ux ≤ ?lpi"by auto hence"- ?lpi ≤ ?ux - 2 * ?lpi"by auto hence pi_ux: "- pi ≤ (?ux - 2 * ?lpi)" using lpi[THEN le_imp_neg_le] by auto
have x_le_ux: "x - k * (2 * pi) - 2 * pi ≤ (?ux - 2 * ?lpi)" using ux lpi by auto have"cos x = cos (x + (-k) * (2 * pi) + (-1::int) * (2 * pi))" unfolding cos_periodic_int .. alsohave"…≤ cos ((?ux - 2 * ?lpi))" using cos_monotone_minus_pi_0'[OF pi_x x_le_ux ux_0] by (simp only: minus_float.rep_eq of_int_minus of_int_1
mult_minus_left mult_1_left) simp alsohave"… = cos ((- (?ux - 2 * ?lpi)))" unfolding uminus_float.rep_eq cos_minus .. alsohave"…≤ (ub_cos prec (- (?ux - 2 * ?lpi)))" using lb_cos_minus[OF pi_ux ux_0] by simp finallyshow ?thesis unfolding u by (simp add: real_of_float_max) qed thus ?thesis unfolding l by auto next case 4: False show ?thesis proof (cases "-2 * ?lpi ≤ ?lx ∧ ?ux ≤ 0") case Cond: True with bnds 1 2 3 4 have l: "l = Float (- 1) 0" and u: "u = max (ub_cos prec (?lx + 2 * ?lpi)) (ub_cos prec (-?ux))" by (auto simp add: bnds_cos_def Let_def)
have"cos x ≤ u" proof (cases "-pi < x - k * (2 * pi)") case True hence"-pi ≤ x - k * (2 * pi)"by simp from negative_ux[OF this Cond[THEN conjunct2]] show ?thesis unfolding u by (simp add: real_of_float_max) next case False hence"x - k * (2 * pi) ≤ -pi"by simp hence pi_x: "x - k * (2 * pi) + 2 * pi ≤ pi"by simp
have"-2 * pi ≤ ?lx"using Cond lpi by auto
hence"0 ≤ x - k * (2 * pi) + 2 * pi"using lx by simp
have lx_0: "0 ≤ real_of_float (?lx + 2 * ?lpi)" using Cond lpi by auto
from 1 and Cond have"¬ -?lpi ≤ ?lx"by auto hence"?lx + 2 * ?lpi ≤ ?lpi"by auto hence pi_lx: "(?lx + 2 * ?lpi) ≤ pi" using lpi[THEN le_imp_neg_le] by auto
have lx_le_x: "(?lx + 2 * ?lpi) ≤ x - k * (2 * pi) + 2 * pi" using lx lpi by auto
have"cos x = cos (x + (-k) * (2 * pi) + (1 :: int) * (2 * pi))" unfolding cos_periodic_int .. alsohave"…≤ cos ((?lx + 2 * ?lpi))" using cos_monotone_0_pi_le[OF lx_0 lx_le_x pi_x] by (simp only: minus_float.rep_eq of_int_minus of_int_1
mult_minus_left mult_1_left) simp alsohave"…≤ (ub_cos prec (?lx + 2 * ?lpi))" using lb_cos[OF lx_0 pi_lx] by simp finallyshow ?thesis unfolding u by (simp add: real_of_float_max) qed thus ?thesis unfolding l by auto next case False with bnds 1 2 3 4 show ?thesis by (auto simp add: bnds_cos_def Let_def) qed qed qed qed qed qed
lemma bnds_cos_lower: "∧x. real_of_float xl ≤ x ==> x ≤ real_of_float xu ==> cos x≤ y ==> real_of_float (fst (bnds_cos prec xl xu)) ≤ y" and bnds_cos_upper: "∧x. real_of_float xl ≤ x ==> x ≤ real_of_float xu ==> y ≤ cos x ==> y ≤ real_of_float (snd (bnds_cos prec xl xu))" for xl xu::float and y::real using bnds_cos[of "fst (bnds_cos prec xl xu)""snd (bnds_cos prec xl xu)" prec] by force+
lift_definition cos_float_interval :: "nat ==> float interval ==> float interval" is"λprec. λ(lx, ux). bnds_cos prec lx ux" using bnds_cos by auto (metis (full_types) order_refl order_trans)
lemma lower_cos_float_interval: "lower (cos_float_interval p x) = fst (bnds_cos p (lower x) (upper x))" by transfer auto lemma upper_cos_float_interval: "upper (cos_float_interval p x) = snd (bnds_cos p (lower x) (upper x))" by transfer auto
lemma cos_float_intervalI: "cos x ∈🪙r cos_float_interval p X"if"x ∈🪙r X" using cos_float_interval[of X p] that by auto
section"Exponential function"
subsection"Compute the series of the exponential function"
fun ub_exp_horner :: "nat ==> nat ==> nat ==> nat ==> float ==> float" and lb_exp_horner :: "nat ==> nat ==> nat ==> nat ==> float ==> float" where "ub_exp_horner prec 0 i k x = 0" | "ub_exp_horner prec (Suc n) i k x = float_plus_up prec (rapprox_rat prec 1 (int k)) (float_round_up prec (x * lb_exp_horner prec n (i + 1) (k * i) x))" | "lb_exp_horner prec 0 i k x = 0" | "lb_exp_horner prec (Suc n) i k x = float_plus_down prec (lapprox_rat prec 1 (int k)) (float_round_down prec (x * ub_exp_horner prec n (i + 1) (k * i) x))"
lemma bnds_exp_horner: assumes"real_of_float x ≤ 0" shows"exp x ∈ {lb_exp_horner prec (get_even n) 1 1 x .. ub_exp_horner prec (get_odd n) 1 1 x}" proof - have f_eq: "fact (Suc n) = fact n * ((λi::nat. i + 1) ^^ n) 1"for n proof - have F: "∧ m. ((λi. i + 1) ^^ n) m = n + m" by (induct n) auto show ?thesis unfolding F by auto qed
note bounds = horner_bounds_nonpos[where f="fact"and lb="lb_exp_horner prec"and ub="ub_exp_horner prec"and j'=0 and s=1,
OF assms f_eq lb_exp_horner.simps ub_exp_horner.simps]
have"lb_exp_horner prec (get_even n) 1 1 x ≤ exp x" proof - have"lb_exp_horner prec (get_even n) 1 1 x ≤ (∑j = 0.. using bounds(1) by auto alsohave"…≤ exp x" proof - obtain t where"∣t∣≤∣real_of_float x∣"and"exp x = (∑m = 0.. using Maclaurin_exp_le unfolding atLeast0LessThan by blast moreoverhave"0 ≤ exp t / (fact (get_even n)) * (real_of_float x) ^ (get_even n)" by (auto simp: zero_le_even_power) ultimatelyshow ?thesis using get_odd exp_gt_zero by auto qed finallyshow ?thesis . qed moreover have"exp x ≤ ub_exp_horner prec (get_odd n) 1 1 x" proof - have x_less_zero: "real_of_float x ^ get_odd n ≤ 0" proof (cases "real_of_float x = 0") case True have"(get_odd n) ≠ 0"using get_odd[THEN odd_pos] by auto thus ?thesis unfolding True power_0_left by auto next case False hence"real_of_float x < 0"using‹real_of_float x ≤ 0›by auto show ?thesis by (rule less_imp_le, auto simp add: ‹real_of_float x 🚫›) qed obtain t where"∣t∣≤∣real_of_float x∣" and"exp x = (∑m = 0.. using Maclaurin_exp_le unfolding atLeast0LessThan by blast moreoverhave"exp t / (fact (get_odd n)) * (real_of_float x) ^ (get_odd n) ≤ 0" by (auto intro!: mult_nonneg_nonpos divide_nonpos_pos simp add: x_less_zero) ultimatelyhave"exp x ≤ (∑j = 0.. using get_odd exp_gt_zero by auto alsohave"…≤ ub_exp_horner prec (get_odd n) 1 1 x" using bounds(2) by auto finallyshow ?thesis . qed ultimatelyshow ?thesis by auto qed
lemma ub_exp_horner_nonneg: "real_of_float x ≤ 0 ==> 0 ≤ real_of_float (ub_exp_horner prec (get_odd n) (Suc 0) (Suc 0) x)" using bnds_exp_horner[of x prec n] by (intro order_trans[OF exp_ge_zero]) auto
subsection"Compute the exponential function on the entire domain"
function ub_exp :: "nat ==> float ==> float"and lb_exp :: "nat ==> float ==> float"where "lb_exp prec x = (if 0 < x then float_divl prec 1 (ub_exp prec (-x)) else let horner = (λ x. let y = lb_exp_horner prec (get_even (prec + 2)) 1 1 x in if y ≤ 0 then Float 1 (- 2) else y) in if x < - 1 then power_down_fl prec (horner (float_divl prec x (- floor_fl x))) (nat (- int_floor_fl x)) else horner x)" | "ub_exp prec x = (if 0 < x then float_divr prec 1 (lb_exp prec (-x)) else if x < - 1 then power_up_fl prec (ub_exp_horner prec (get_odd (prec + 2)) 1 1 (float_divr prec x (- floor_fl x))) (nat (- int_floor_fl x)) else ub_exp_horner prec (get_odd (prec + 2)) 1 1 x)" by pat_completeness auto termination by (relation "measure (λ v. let (prec, x) = case_sum id id v in (if 0 < x then 1 else 0))") auto
lemma exp_m1_ge_quarter: "(1 / 4 :: real) ≤ exp (- 1)" proof - have eq4: "4 = Suc (Suc (Suc (Suc 0)))"by auto have"1 / 4 = (Float 1 (- 2))" unfolding Float_num by auto alsohave"…≤ lb_exp_horner 3 (get_even 3) 1 1 (- 1)" by (subst less_eq_float.rep_eq [symmetric]) code_simp alsohave"…≤ exp (- 1 :: float)" using bnds_exp_horner[where x="- 1"] by auto finallyshow ?thesis by simp qed
lemma lb_exp_pos: assumes"¬ 0 < x" shows"0 < lb_exp prec x" proof - let"?lb_horner x" = "lb_exp_horner prec (get_even (prec + 2)) 1 1 x" let"?horner x" = "let y = ?lb_horner x in if y ≤ 0 then Float 1 (- 2) else y" have pos_horner: "0 < ?horner x"for x unfolding Let_def by (cases "?lb_horner x ≤ 0") auto moreoverhave"0 < real_of_float ((?horner x) ^ num)"for x :: float and num :: nat proof - have"0 < real_of_float (?horner x) ^ num"using‹0 🚫horner x›by simp alsohave"… = (?horner x) ^ num"by auto finallyshow ?thesis . qed ultimatelyshow ?thesis unfolding lb_exp.simps if_not_P[OF ‹¬ 0 🚫›] Let_def by (cases "floor_fl x", cases "x < - 1")
(auto simp: real_power_up_fl real_power_down_fl intro!: power_up_less power_down_pos) qed
have"real_of_float x ≤ 0"and"¬ x > 0" using‹x ≤ 0›by auto show ?thesis proof (cases "x < - 1") case False hence"- 1 ≤ real_of_float x"by auto show ?thesis proof (cases "?lb_exp_horner x ≤ 0") case True from‹¬ x 🚫 1› have"- 1 ≤ real_of_float x"by auto hence"exp (- 1) ≤ exp x" unfolding exp_le_cancel_iff . from order_trans[OF exp_m1_ge_quarter this] have"Float 1 (- 2) ≤ exp x" unfolding Float_num . with True show ?thesis using bnds_exp_horner ‹real_of_float x ≤ 0›‹¬ x > 0›‹¬ x 🚫 1›by auto next case False thus ?thesis using bnds_exp_horner ‹real_of_float x ≤ 0›‹¬ x > 0›‹¬ x 🚫 1›by (auto simp add: Let_def) qed next case True let ?num = "nat (- int_floor_fl x)"
have"real_of_int (int_floor_fl x) < - 1" using int_floor_fl[of x] ‹x 🚫 1›by simp hence"real_of_int (int_floor_fl x) < 0"by simp hence"int_floor_fl x < 0"by auto hence"1 ≤ - int_floor_fl x"by auto hence"0 < nat (- int_floor_fl x)"by auto hence"0 < ?num"by auto hence"real ?num ≠ 0"by auto have num_eq: "real ?num = - int_floor_fl x" using‹0 🚫 (- int_floor_fl x)›by auto have"0 < - int_floor_fl x" using‹0 🚫num›[unfolded of_nat_less_iff[symmetric]] by simp hence"real_of_int (int_floor_fl x) < 0" unfolding less_float_def by auto have fl_eq: "real_of_int (- int_floor_fl x) = real_of_float (- floor_fl x)" by (simp add: floor_fl_def int_floor_fl_def) from‹0 🚫 int_floor_fl x›have"0 ≤ real_of_float (- floor_fl x)" by (simp add: floor_fl_def int_floor_fl_def) from‹real_of_int (int_floor_fl x) 🚫›have"real_of_float (floor_fl x) < 0" by (simp add: floor_fl_def int_floor_fl_def) have"exp x ≤ ub_exp prec x" proof - have div_less_zero: "real_of_float (float_divr prec x (- floor_fl x)) ≤ 0" using float_divr_nonpos_pos_upper_bound[OF ‹real_of_float x ≤ 0›‹0 ≤ real_of_float (- floor_fl x)›] unfolding less_eq_float_def zero_float.rep_eq .
have"exp x = exp (?num * (x / ?num))" using‹real ?num ≠ 0›by auto alsohave"… = exp (x / ?num) ^ ?num" unfolding exp_of_nat_mult .. alsohave"…≤ exp (float_divr prec x (- floor_fl x)) ^ ?num" unfolding num_eq fl_eq by (rule power_mono, rule exp_le_cancel_iff[THEN iffD2], rule float_divr) auto alsohave"…≤ (?ub_exp_horner (float_divr prec x (- floor_fl x))) ^ ?num" unfolding real_of_float_power by (rule power_mono, rule bnds_exp_horner[OF div_less_zero, unfolded atLeastAtMost_iff, THEN conjunct2], auto) alsohave"…≤ real_of_float (power_up_fl prec (?ub_exp_horner (float_divr prec x (- floor_fl x))) ?num)" by (auto simp add: real_power_up_fl intro!: power_up ub_exp_horner_nonneg div_less_zero) finallyshow ?thesis unfolding ub_exp.simps if_not_P[OF ‹¬ 0 🚫›] if_P[OF ‹x 🚫 1›] floor_fl_def Let_def . qed moreover have"lb_exp prec x ≤ exp x" proof - let ?divl = "float_divl prec x (- floor_fl x)" let ?horner = "?lb_exp_horner ?divl"
show ?thesis proof (cases "?horner ≤ 0") case False hence"0 ≤ real_of_float ?horner"by auto
have div_less_zero: "real_of_float (float_divl prec x (- floor_fl x)) ≤ 0" using‹real_of_float (floor_fl x) 🚫›‹real_of_float x ≤ 0› by (auto intro!: order_trans[OF float_divl] divide_nonpos_neg)
have"(?lb_exp_horner (float_divl prec x (- floor_fl x))) ^ ?num ≤ exp (float_divl prec x (- floor_fl x)) ^ ?num" using‹0 ≤ real_of_float ?horner›[unfolded floor_fl_def[symmetric]]
bnds_exp_horner[OF div_less_zero, unfolded atLeastAtMost_iff, THEN conjunct1] by (auto intro!: power_mono) alsohave"…≤ exp (x / ?num) ^ ?num" unfolding num_eq fl_eq using float_divl by (auto intro!: power_mono simp del: uminus_float.rep_eq) alsohave"… = exp (?num * (x / ?num))" unfolding exp_of_nat_mult .. alsohave"… = exp x" using‹real ?num ≠ 0›by auto finallyshow ?thesis using False unfolding lb_exp.simps if_not_P[OF ‹¬ 0 🚫›] if_P[OF ‹x 🚫 1›]
int_floor_fl_def Let_def if_not_P[OF False] by (auto simp: real_power_down_fl intro!: power_down_le) next case True have"power_down_fl prec (Float 1 (- 2)) ?num ≤ (Float 1 (- 2)) ^ ?num" by (metis Float_le_zero_iff less_imp_le linorder_not_less
not_numeral_le_zero numeral_One power_down_fl) thenhave"power_down_fl prec (Float 1 (- 2)) ?num ≤ real_of_float (Float 1 (- 2)) ^ ?num" by simp also have"real_of_float (floor_fl x) ≠ 0"and"real_of_float (floor_fl x) ≤ 0" using‹real_of_float (floor_fl x) 🚫›by auto from divide_right_mono_neg[OF floor_fl[of x] ‹real_of_float (floor_fl x) ≤ 0›, unfolded divide_self[OF ‹real_of_float (floor_fl x) ≠ 0›]] have"- 1 ≤ x / (- floor_fl x)" unfolding minus_float.rep_eq by auto from order_trans[OF exp_m1_ge_quarter this[unfolded exp_le_cancel_iff[where x="- 1", symmetric]]] have"Float 1 (- 2) ≤ exp (x / (- floor_fl x))" unfolding Float_num . hence"real_of_float (Float 1 (- 2)) ^ ?num ≤ exp (x / (- floor_fl x)) ^ ?num" by (metis Float_num(5) power_mono zero_le_divide_1_iff zero_le_numeral) alsohave"… = exp x" unfolding num_eq fl_eq exp_of_nat_mult[symmetric] using‹real_of_float (floor_fl x) ≠ 0›by auto finallyshow ?thesis unfolding lb_exp.simps if_not_P[OF ‹¬ 0 🚫›] if_P[OF ‹x 🚫 1›]
int_floor_fl_def Let_def if_P[OF True] real_of_float_power . qed qed ultimatelyshow ?thesis by auto qed qed
lemma exp_boundaries: "exp x ∈ { lb_exp prec x .. ub_exp prec x }" proof - show ?thesis proof (cases "0 < x") case False hence"x ≤ 0"by auto from exp_boundaries'[OF this] show ?thesis . next case True hence"-x ≤ 0"by auto
have"lb_exp prec x ≤ exp x" proof - from exp_boundaries'[OF ‹-x ≤ 0›] have ub_exp: "exp (- real_of_float x) ≤ ub_exp prec (-x)" unfolding atLeastAtMost_iff minus_float.rep_eq by auto
have"float_divl prec 1 (ub_exp prec (-x)) ≤ 1 / ub_exp prec (-x)" using float_divl[where x=1] by auto alsohave"…≤ exp x" using ub_exp[unfolded inverse_le_iff_le[OF order_less_le_trans[OF exp_gt_zero ub_exp]
exp_gt_zero, symmetric]] unfolding exp_minus nonzero_inverse_inverse_eq[OF exp_not_eq_zero] inverse_eq_divide by auto finallyshow ?thesis unfolding lb_exp.simps if_P[OF True] . qed moreover have"exp x ≤ ub_exp prec x" proof - have"¬ 0 < -x"using‹0 🚫›by auto
from exp_boundaries'[OF ‹-x ≤ 0›] have lb_exp: "lb_exp prec (-x) ≤ exp (- real_of_float x)" unfolding atLeastAtMost_iff minus_float.rep_eq by auto
have"exp x ≤ (1 :: float) / lb_exp prec (-x)" using lb_exp lb_exp_pos[OF ‹¬ 0 🚫x›, of prec] by (simp del: lb_exp.simps add: exp_minus field_simps) alsohave"…≤ float_divr prec 1 (lb_exp prec (-x))" using float_divr . finallyshow ?thesis unfolding ub_exp.simps if_P[OF True] . qed ultimatelyshow ?thesis by auto qed qed
lemma bnds_exp: "∀(x::real) lx ux. (l, u) = (lb_exp prec lx, ub_exp prec ux) ∧ x ∈ {lx .. ux} ⟶ l ≤ exp x ∧ exp x ≤ u" proof (rule allI, rule allI, rule allI, rule impI) fix x :: real and lx ux assume"(l, u) = (lb_exp prec lx, ub_exp prec ux) ∧ x ∈ {lx .. ux}" hence l: "lb_exp prec lx = l "and u: "ub_exp prec ux = u"and x: "x ∈ {lx .. ux}" by auto show"l ≤ exp x ∧ exp x ≤ u" proof show"l ≤ exp x" proof - from exp_boundaries[of lx prec, unfolded l] have"l ≤ exp lx"by (auto simp del: lb_exp.simps) alsohave"…≤ exp x"using x by auto finallyshow ?thesis . qed show"exp x ≤ u" proof - have"exp x ≤ exp ux"using x by auto alsohave"…≤ u"using exp_boundaries[of ux prec, unfolded u] by (auto simp del: ub_exp.simps) finallyshow ?thesis . qed qed qed
lemmas [simp del] = lb_exp.simps ub_exp.simps
lemma lb_exp: "exp x ≤ y ==> lb_exp prec x ≤ y" and ub_exp: "y ≤ exp x ==> y ≤ ub_exp prec x" for x::float and y::real using exp_boundaries[of x prec] by auto
lemma lower_exp_float_interval: "lower (exp_float_interval p x) = lb_exp p (lower x)" by transfer auto lemma upper_exp_float_interval: "upper (exp_float_interval p x) = ub_exp p (upper x)" by transfer auto
lemma exp_float_interval: "exp ` set_of (real_interval x) ⊆ set_of (real_interval (exp_float_interval p x))" using exp_boundaries by (auto simp: set_of_eq lower_exp_float_interval upper_exp_float_interval lb_exp ub_exp)
lemma exp_float_intervalI: "exp x ∈🪙r exp_float_interval p X"if"x ∈🪙r X" using exp_float_interval[of X p] that by auto
section"Logarithm"
subsection"Compute the logarithm series"
fun ub_ln_horner :: "nat ==> nat ==> nat ==> float ==> float" and lb_ln_horner :: "nat ==> nat ==> nat ==> float ==> float"where "ub_ln_horner prec 0 i x = 0" | "ub_ln_horner prec (Suc n) i x = float_plus_up prec (rapprox_rat prec 1 (int i)) (- float_round_down prec (x * lb_ln_horner prec n (Suc i) x))" | "lb_ln_horner prec 0 i x = 0" | "lb_ln_horner prec (Suc n) i x = float_plus_down prec (lapprox_rat prec 1 (int i)) (- float_round_up prec (x * ub_ln_horner prec n (Suc i) x))"
lemma ln_bounds: assumes"0 ≤ x" and"x < 1" shows"(∑i=0..<2*n. (- 1) ^ i * (1 / real (i + 1)) * x ^ (Suc i)) ≤ ln (x + 1)" (is"?lb") and"ln (x + 1) ≤ (∑i=0..<2*n + 1. (- 1) ^ i * (1 / real (i + 1)) * x ^ (Suc i))" (is"?ub") proof - let"?a n" = "(1/real (n +1)) * x ^ (Suc n)"
have ln_eq: "(∑ i. (- 1) ^ i * ?a i) = ln (x + 1)" using ln_series[of "x + 1"] ‹0 ≤ x›‹x 🚫›by auto
have"norm x < 1"using assms by auto have"?a <---- 0"unfolding Suc_eq_plus1[symmetric] inverse_eq_divide[symmetric] using tendsto_mult[OF LIMSEQ_inverse_real_of_nat LIMSEQ_Suc[OF LIMSEQ_power_zero[OF ‹norm x 🚫›]]] by auto have"0 ≤ ?a n"for n by (rule mult_nonneg_nonneg) (auto simp: ‹0 ≤ x›) have"?a (Suc n) ≤ ?a n"for n unfolding inverse_eq_divide[symmetric] proof (rule mult_mono) show"0 ≤ x ^ Suc (Suc n)" by (auto simp add: ‹0 ≤ x›) have"x ^ Suc (Suc n) ≤ x ^ Suc n * 1" unfolding power_Suc2 mult.assoc[symmetric] by (rule mult_left_mono, fact less_imp_le[OF ‹x 🚫›]) (auto simp: ‹0 ≤ x›) thus"x ^ Suc (Suc n) ≤ x ^ Suc n"by auto qed auto from summable_Leibniz'(2,4)[OF ‹?a <---- 0›‹∧n. 0 ≤ ?a n›, OF ‹∧n. ?a (Suc n) ≤ ?a n›, unfolded ln_eq] show ?lb and ?ub unfolding atLeast0LessThan by auto qed
lemma ln_float_bounds: assumes"0 ≤ real_of_float x" and"real_of_float x < 1" shows"x * lb_ln_horner prec (get_even n) 1 x ≤ ln (x + 1)" (is"?lb ≤ ?ln") and"ln (x + 1) ≤ x * ub_ln_horner prec (get_odd n) 1 x" (is"?ln ≤ ?ub") proof - obtain ev where ev: "get_even n = 2 * ev"using get_even_double .. obtain od where od: "get_odd n = 2 * od + 1"using get_odd_double ..
let"?s n" = "(- 1) ^ n * (1 / real (1 + n)) * (real_of_float x)^(Suc n)"
have"?lb ≤ sum ?s {0 ..< 2 * ev}" unfolding power_Suc2 mult.assoc[symmetric] times_float.rep_eq sum_distrib_right[symmetric] unfolding mult.commute[of "real_of_float x"] ev using horner_bounds(1)[where G="λ i k. Suc k"and F="λx. x"and f="λx. x" and lb="λn i k x. lb_ln_horner prec n k x" and ub="λn i k x. ub_ln_horner prec n k x"and j'=1 and n="2*ev",
OF ‹0 ≤ real_of_float x› refl lb_ln_horner.simps ub_ln_horner.simps] ‹0 ≤ real_of_float x› unfolding real_of_float_power by (rule mult_right_mono) alsohave"…≤ ?ln" using ln_bounds(1)[OF ‹0 ≤ real_of_float x›‹real_of_float x 🚫›] by auto finallyshow"?lb ≤ ?ln" .
have"?ln ≤ sum ?s {0 ..< 2 * od + 1}" using ln_bounds(2)[OF ‹0 ≤ real_of_float x›‹real_of_float x 🚫›] by auto alsohave"…≤ ?ub" unfolding power_Suc2 mult.assoc[symmetric] times_float.rep_eq sum_distrib_right[symmetric] unfolding mult.commute[of "real_of_float x"] od using horner_bounds(2)[where G="λ i k. Suc k"and F="λx. x"and f="λx. x"and lb="λn i k x. lb_ln_horner prec n k x"and ub="λn i k x. ub_ln_horner prec n k x"and j'=1 and n="2 * od + 1",
OF ‹0 ≤ real_of_float x› refl lb_ln_horner.simps ub_ln_horner.simps] ‹0 ≤ real_of_float x› unfolding real_of_float_power by (rule mult_right_mono) finallyshow"?ln ≤ ?ub" . qed
lemma ln_add: fixes x :: real assumes"0 < x"and"0 < y" shows"ln (x + y) = ln x + ln (1 + y / x)" proof - have"x ≠ 0"using assms by auto have"x + y = x * (1 + y / x)" unfolding distrib_left times_divide_eq_right nonzero_mult_div_cancel_left[OF ‹x ≠ 0›] by auto moreover have"0 < y / x"using assms by auto hence"0 < 1 + y / x"by auto ultimatelyshow ?thesis using ln_mult assms by auto qed
have ln2_sum: "ln 2 = ln (1/2 + 1) + ln (1 / 3 + 1::real)" using ln_add[of "3 / 2""1 / 2"] by auto have lb3: "?lthird ≤ 1 / 3"using lapprox_rat[of prec 1 3] by auto hence lb3_ub: "real_of_float ?lthird < 1"by auto have lb3_lb: "0 ≤ real_of_float ?lthird"using lapprox_rat_nonneg[of 1 3] by auto have ub3: "1 / 3 ≤ ?uthird"using rapprox_rat[of 1 3] by auto hence ub3_lb: "0 ≤ real_of_float ?uthird"by auto
have lb2: "0 ≤ real_of_float (Float 1 (- 1))"and ub2: "real_of_float (Float 1 (- 1)) < 1" unfolding Float_num by auto
have"0 ≤ (1::int)"and"0 < (3::int)"by auto have ub3_ub: "real_of_float ?uthird < 1" by (simp add: Float.compute_rapprox_rat Float.compute_lapprox_rat rapprox_posrat_less1)
have third_gt0: "(0 :: real) < 1 / 3 + 1"by auto have uthird_gt0: "0 < real_of_float ?uthird + 1"using ub3_lb by auto have lthird_gt0: "0 < real_of_float ?lthird + 1"using lb3_lb by auto
subsection"Compute the logarithm in the entire domain"
function ub_ln :: "nat ==> float ==> float option"and lb_ln :: "nat ==> float ==> float option"where "ub_ln prec x = (if x ≤ 0 then None else if x < 1 then Some (- the (lb_ln prec (float_divl (max prec 1) 1 x))) else let horner = λx. float_round_up prec (x * ub_ln_horner prec (get_odd prec) 1 x) in if x ≤ Float 3 (- 1) then Some (horner (x - 1)) else if x < Float 1 1 then Some (float_round_up prec (horner (Float 1 (- 1)) + horner (x * rapprox_rat prec 2 3 - 1))) else let l = bitlen (mantissa x) - 1 in Some (float_plus_up prec (float_round_up prec (ub_ln2 prec * (Float (exponent x + l) 0))) (horner (Float (mantissa x) (- l) - 1))))" | "lb_ln prec x = (if x ≤ 0 then None else if x < 1 then Some (- the (ub_ln prec (float_divr prec 1 x))) else let horner = λx. float_round_down prec (x * lb_ln_horner prec (get_even prec) 1 x) in if x ≤ Float 3 (- 1) then Some (horner (x - 1)) else if x < Float 1 1 then Some (float_round_down prec (horner (Float 1 (- 1)) + horner (max (x * lapprox_rat prec 2 3 - 1) 0))) else let l = bitlen (mantissa x) - 1 in Some (float_plus_down prec (float_round_down prec (lb_ln2 prec * (Float (exponent x + l) 0))) (horner (Float (mantissa x) (- l) - 1))))" by pat_completeness auto
termination proof (relation "measure (λ v. let (prec, x) = case_sum id id v in (if x < 1 then 1 else 0))", auto) fix prec and x :: float assume"¬ real_of_float x ≤ 0"and"real_of_float x < 1"and"real_of_float (float_divl (max prec (Suc 0)) 1 x) < 1" hence"0 < real_of_float x""1 ≤ max prec (Suc 0)""real_of_float x < 1" by auto from float_divl_pos_less1_bound[OF ‹0 🚫 x›‹real_of_float x 🚫›[THEN less_imp_le] ‹1 ≤ max prec (Suc 0)›] show False using‹real_of_float (float_divl (max prec (Suc 0)) 1 x) 🚫›by auto next fix prec x assume"¬ real_of_float x ≤ 0"and"real_of_float x < 1"and"real_of_float (float_divr prec 1 x) < 1" hence"0 < x"by auto from float_divr_pos_less1_lower_bound[OF ‹0 🚫›, of prec] ‹real_of_float x 🚫›show False using‹real_of_float (float_divr prec 1 x) 🚫›by auto qed
lemma compute_ln[code]: fixes m e defines"x ≡ Float m e" shows"ub_ln prec x = (if x ≤ 0 then None else if x < 1 then Some (- the (lb_ln prec (float_divl (max prec 1) 1 x))) else let horner = λx. float_round_up prec (x * ub_ln_horner prec (get_odd prec) 1 x) in if x ≤ Float 3 (- 1) then Some (horner (x - 1)) else if x < Float 1 1 then Some (float_round_up prec (horner (Float 1 (- 1)) + horner (x * rapprox_rat prec 2 3 - 1))) else let l = bitlen m - 1 in Some (float_plus_up prec (float_round_up prec (ub_ln2 prec * (Float (e + l) 0))) (horner (Float m (- l) - 1))))"
(is ?th1) and"lb_ln prec x = (if x ≤ 0 then None else if x < 1 then Some (- the (ub_ln prec (float_divr prec 1 x))) else let horner = λx. float_round_down prec (x * lb_ln_horner prec (get_even prec) 1 x) in if x ≤ Float 3 (- 1) then Some (horner (x - 1)) else if x < Float 1 1 then Some (float_round_down prec (horner (Float 1 (- 1)) + horner (max (x * lapprox_rat prec 2 3 - 1) 0))) else let l = bitlen m - 1 in Some (float_plus_down prec (float_round_down prec (lb_ln2 prec * (Float (e + l) 0))) (horner (Float m (- l) - 1))))"
(is ?th2) proof - from assms Float_pos_eq_mantissa_pos have"x > 0 ==> m > 0" by simp thus ?th1 ?th2 using Float_representation_aux[of m e] unfolding x_def[symmetric] by (auto dest: not_le_imp_less) qed
lemma ln_shifted_float: assumes"0 < m" shows"ln (Float m e) = ln 2 * (e + (bitlen m - 1)) + ln (Float m (- (bitlen m - 1)))" proof - let ?B = "2^nat (bitlen m - 1)"
define bl where"bl = bitlen m - 1" have"0 < real_of_int m"and"∧X. (0 :: real) < 2^X"and"0 < (2 :: real)"and"m ≠ 0" using assms by auto hence"0 ≤ bl"by (simp add: bitlen_alt_def bl_def) show ?thesis proof (cases "0 ≤ e") case True thus ?thesis unfolding bl_def[symmetric] using‹0 🚫 m›‹0 ≤ bl› apply (simp add: ln_mult) by argo next case False hence"0 < -e"by auto have lne: "ln (2 powr real_of_int e) = ln (inverse (2 powr - e))" by (simp add: powr_minus) hence pow_gt0: "(0::real) < 2^nat (-e)" by auto hence inv_gt0: "(0::real) < inverse (2^nat (-e))" by auto show ?thesis using False unfolding bl_def[symmetric] using‹0 🚫 m›‹0 ≤ bl› by (auto simp add: lne ln_mult ln_powr ln_div field_simps) qed qed
lemma ub_ln_lb_ln_bounds': assumes"1 ≤ x" shows"the (lb_ln prec x) ≤ ln x ∧ ln x ≤ the (ub_ln prec x)"
(is"?lb ≤ ?ln ∧ ?ln ≤ ?ub") proof (cases "x < Float 1 1") case True hence"real_of_float (x - 1) < 1"and"real_of_float x < 2"by auto have"¬ x ≤ 0"and"¬ x < 1"using‹1 ≤ x›by auto hence"0 ≤ real_of_float (x - 1)"using‹1 ≤ x›by auto
have [simp]: "(Float 3 (- 1)) = 3 / 2"by simp
show ?thesis proof (cases "x ≤ Float 3 (- 1)") case True show ?thesis unfolding lb_ln.simps unfolding ub_ln.simps Let_def using ln_float_bounds[OF ‹0 ≤ real_of_float (x - 1)›‹real_of_float (x - 1) 🚫›, of prec] ‹¬ x ≤ 0›‹¬ x 🚫› True by (auto intro!: float_round_down_le float_round_up_le) next case False hence *: "3 / 2 < x"by auto
with ln_add[of "3 / 2""x - 3 / 2"] have add: "ln x = ln (3 / 2) + ln (real_of_float x * 2 / 3)" by (auto simp add: algebra_simps diff_divide_distrib)
{ have up: "real_of_float (rapprox_rat prec 2 3) ≤ 1" by (rule rapprox_rat_le1) simp_all have low: "2 / 3 ≤ rapprox_rat prec 2 3" by (rule order_trans[OF _ rapprox_rat]) simp from mult_less_le_imp_less[OF * low] * have pos: "0 < real_of_float (x * rapprox_rat prec 2 3 - 1)"by auto
have"ln (real_of_float x * 2/3) ≤ ln (real_of_float (x * rapprox_rat prec 2 3 - 1) + 1)" proof (rule ln_le_cancel_iff[symmetric, THEN iffD1]) show"real_of_float x * 2 / 3 ≤ real_of_float (x * rapprox_rat prec 2 3 - 1) + 1" using * low by auto show"0 < real_of_float x * 2 / 3"using * by simp show"0 < real_of_float (x * rapprox_rat prec 2 3 - 1) + 1"using pos by auto qed alsohave"…≤ ?ub_horner (x * rapprox_rat prec 2 3 - 1)" proof (rule float_round_up_le, rule ln_float_bounds(2)) from mult_less_le_imp_less[OF ‹real_of_float x 🚫› up] low * show"real_of_float (x * rapprox_rat prec 2 3 - 1) < 1"by auto show"0 ≤ real_of_float (x * rapprox_rat prec 2 3 - 1)"using pos by auto qed finallyhave"ln x ≤ ?ub_horner (Float 1 (-1)) + ?ub_horner ((x * rapprox_rat prec 2 3 - 1))" using ln_float_bounds(2)[of "Float 1 (- 1)" prec prec] add by (auto intro!: add_mono float_round_up_le) note float_round_up_le[OF this, of prec]
} moreover
{ let ?max = "max (x * lapprox_rat prec 2 3 - 1) 0"
have up: "lapprox_rat prec 2 3 ≤ 2/3" by (rule order_trans[OF lapprox_rat], simp)
have low: "0 ≤ real_of_float (lapprox_rat prec 2 3)" using lapprox_rat_nonneg[of 2 3 prec] by simp
have"?lb_horner ?max ≤ ln (real_of_float ?max + 1)" proof (rule float_round_down_le, rule ln_float_bounds(1)) from mult_less_le_imp_less[OF ‹real_of_float x 🚫› up] * low show"real_of_float ?max < 1"by (cases "real_of_float (lapprox_rat prec 2 3) = 0",
auto simp add: real_of_float_max) show"0 ≤ real_of_float ?max"by (auto simp add: real_of_float_max) qed alsohave"…≤ ln (real_of_float x * 2/3)" proof (rule ln_le_cancel_iff[symmetric, THEN iffD1]) show"0 < real_of_float ?max + 1"by (auto simp add: real_of_float_max) show"0 < real_of_float x * 2/3"using * by auto show"real_of_float ?max + 1 ≤ real_of_float x * 2/3"using * up by (cases "0 < real_of_float x * real_of_float (lapprox_posrat prec 2 3) - 1",
auto simp add: max_def) qed finallyhave"?lb_horner (Float 1 (- 1)) + ?lb_horner ?max ≤ ln x" using ln_float_bounds(1)[of "Float 1 (- 1)" prec prec] add by (auto intro!: add_mono float_round_down_le) note float_round_down_le[OF this, of prec]
} ultimately show ?thesis unfolding lb_ln.simps unfolding ub_ln.simps Let_def using‹¬ x ≤ 0›‹¬ x 🚫› True False by auto qed next case False hence"¬ x ≤ 0"and"¬ x < 1""0 < x""¬ x ≤ Float 3 (- 1)" using‹1 ≤ x›by auto show ?thesis proof -
define m where"m = mantissa x"
define e where"e = exponent x" from Float_mantissa_exponent[of x] have Float: "x = Float m e" by (simp add: m_def e_def) let ?s = "Float (e + (bitlen m - 1)) 0" let ?x = "Float m (- (bitlen m - 1))"
have"0 < m"and"m ≠ 0"using‹0 🚫› Float powr_gt_zero[of 2 e] by (auto simp add: zero_less_mult_iff)
define bl where"bl = bitlen m - 1" thenhave bitlen: "bitlen m = bl + 1" by simp hence"bl ≥ 0" using‹m > 0›by (auto simp add: bitlen_alt_def) have"1 ≤ Float m e" using‹1 ≤ x› Float unfolding less_eq_float_def by auto from bitlen_div[OF ‹0 🚫›] float_gt1_scale[OF ‹1 ≤ Float m e›] ‹bl ≥ 0› have x_bnds: "0 ≤ real_of_float (?x - 1)""real_of_float (?x - 1) < 1" using abs_real_le_2_powr_bitlen [of m] ‹m > 0› by (simp_all add: bitlen powr_realpow [symmetric] powr_minus powr_add field_simps)
{ have"real_of_float (lb_ln2 prec) * real_of_float (Float (e + (bitlen m - 1)) 0) ≤ ln 2 * real_of_int (e + (bitlen m - 1))" proof (rule mult_mono) from float_gt1_scale[OF ‹1 ≤ Float m e›] show"0 ≤ real_of_float (Float (e + (bitlen m - 1)) 0)"by simp qed (use lb_ln2[of prec] in auto) thenhave"float_round_down prec (lb_ln2 prec * ?s) ≤ ln 2 * (e + (bitlen m - 1))"
(is"real_of_float ?lb2 ≤ _") by (simp add: Interval_Float.float_round_down_le) moreover from ln_float_bounds(1)[OF x_bnds] have"float_round_down prec ((?x - 1) * lb_ln_horner prec (get_even prec) 1 (?x - 1)) ≤ ln ?x" (is"real_of_float ?lb_horner ≤ _") by (auto intro!: float_round_down_le) ultimatelyhave"float_plus_down prec ?lb2 ?lb_horner ≤ ln x" unfolding Float ln_shifted_float[OF ‹0 🚫›, of e] by (auto intro!: float_plus_down_le)
} moreover
{ from ln_float_bounds(2)[OF x_bnds] have"ln ?x ≤ float_round_up prec ((?x - 1) * ub_ln_horner prec (get_odd prec) 1 (?x - 1))"
(is"_ ≤ real_of_float ?ub_horner") by (auto intro!: float_round_up_le) moreover have"ln 2 * (e + (bitlen m - 1)) ≤ float_round_up prec (ub_ln2 prec * ?s)"
(is"_ ≤ real_of_float ?ub2") apply (rule float_round_up_le) unfolding nat_0 power_0 mult_1_right times_float.rep_eq using ub_ln2[of prec] proof (rule mult_mono) from float_gt1_scale[OF ‹1 ≤ Float m e›] show"0 ≤ real_of_int (e + (bitlen m - 1))"by auto have"0 ≤ ln (2 :: real)"by simp thus"0 ≤ real_of_float (ub_ln2 prec)"using ub_ln2[of prec] by arith qed auto ultimatelyhave"ln x ≤ float_plus_up prec ?ub2 ?ub_horner" unfolding Float ln_shifted_float[OF ‹0 🚫›, of e] by (auto intro!: float_plus_up_le)
} ultimatelyshow ?thesis unfolding lb_ln.simps unfolding ub_ln.simps unfolding if_not_P[OF ‹¬ x ≤ 0›] if_not_P[OF ‹¬ x 🚫›]
if_not_P[OF False] if_not_P[OF ‹¬ x ≤ Float 3 (- 1)›] Let_def unfolding plus_float.rep_eq e_def[symmetric] m_def[symmetric] by simp qed qed
lemma ub_ln_lb_ln_bounds: assumes"0 < x" shows"the (lb_ln prec x) ≤ ln x ∧ ln x ≤ the (ub_ln prec x)"
(is"?lb ≤ ?ln ∧ ?ln ≤ ?ub") proof (cases "x < 1") case False hence"1 ≤ x" unfolding less_float_def less_eq_float_def by auto show ?thesis using ub_ln_lb_ln_bounds'[OF ‹1 ≤ x›] . next case True have"¬ x ≤ 0"using‹0 🚫›by auto from True have"real_of_float x ≤ 1""x ≤ 1" by simp_all have"0 < real_of_float x"and"real_of_float x ≠ 0" using‹0 🚫›by auto hence A: "0 < 1 / real_of_float x"by auto
{ let ?divl = "float_divl (max prec 1) 1 x" have A': "1 ≤ ?divl"using float_divl_pos_less1_bound[OF ‹0 🚫 x›‹real_of_float x ≤1›] by auto hence B: "0 < real_of_float ?divl"by auto
have"ln ?divl ≤ ln (1 / x)"unfolding ln_le_cancel_iff[OF B A] using float_divl[of _ 1 x] by auto hence"ln x ≤ - ln ?divl" by (simp add: ‹real_of_float x ≠ 0› ln_div) from this ub_ln_lb_ln_bounds'[OF A', THEN conjunct1, THEN le_imp_neg_le] have"?ln ≤ - the (lb_ln prec ?divl)"unfolding uminus_float.rep_eq by (rule order_trans)
} moreover
{ let ?divr = "float_divr prec 1 x" have A': "1 ≤ ?divr"using float_divr_pos_less1_lower_bound[OF ‹0 🚫›‹x ≤ 1›] unfolding less_eq_float_def less_float_def by auto hence B: "0 < real_of_float ?divr"by auto
have"ln (1 / x) ≤ ln ?divr"unfolding ln_le_cancel_iff[OF A B] using float_divr[of 1 x] by auto hence"- ln ?divr ≤ ln x" by (simp add: ‹real_of_float x ≠ 0› ln_div) from ub_ln_lb_ln_bounds'[OF A', THEN conjunct2, THEN le_imp_neg_le] this have"- the (ub_ln prec ?divr) ≤ ?ln"unfolding uminus_float.rep_eq by (rule order_trans)
} ultimatelyshow ?thesis unfolding lb_ln.simps[where x=x] ub_ln.simps[where x=x] unfolding if_not_P[OF ‹¬ x ≤ 0›] if_P[OF True] by auto qed
lemma lb_ln: assumes"Some y = lb_ln prec x" shows"y ≤ ln x"and"0 < real_of_float x" proof - have"0 < x" proof (rule ccontr) assume"¬ 0 < x" hence"x ≤ 0" unfolding less_eq_float_def less_float_def by auto thus False using assms by auto qed thus"0 < real_of_float x"by auto have"the (lb_ln prec x) ≤ ln x" using ub_ln_lb_ln_bounds[OF ‹0 🚫›] .. thus"y ≤ ln x" unfolding assms[symmetric] by auto qed
lemma ub_ln: assumes"Some y = ub_ln prec x" shows"ln x ≤ y"and"0 < real_of_float x" proof - have"0 < x" proof (rule ccontr) assume"¬ 0 < x" hence"x ≤ 0"by auto thus False using assms by auto qed thus"0 < real_of_float x"by auto have"ln x ≤ the (ub_ln prec x)" using ub_ln_lb_ln_bounds[OF ‹0 🚫›] .. thus"ln x ≤ y" unfolding assms[symmetric] by auto qed
lemma bnds_ln: "∀(x::real) lx ux. (Some l, Some u) = (lb_ln prec lx, ub_ln prec ux) ∧ x ∈ {lx .. ux} ⟶ l ≤ ln x ∧ ln x ≤ u" proof (rule allI, rule allI, rule allI, rule impI) fix x :: real fix lx ux assume"(Some l, Some u) = (lb_ln prec lx, ub_ln prec ux) ∧ x ∈ {lx .. ux}" hence l: "Some l = lb_ln prec lx "and u: "Some u = ub_ln prec ux"and x: "x ∈ {lx .. ux}" by auto
have"ln ux ≤ u"and"0 < real_of_float ux" using ub_ln u by auto have"l ≤ ln lx"and"0 < real_of_float lx"and"0 < x" using lb_ln[OF l] x by auto
from ln_le_cancel_iff[OF ‹0 🚫 lx›‹0 🚫›] ‹l ≤ ln lx› have"l ≤ ln x" using x unfolding atLeastAtMost_iff by auto moreover from ln_le_cancel_iff[OF ‹0 🚫›‹0 🚫 ux›] ‹ln ux ≤ real_of_float u› have"ln x ≤ u" using x unfolding atLeastAtMost_iff by auto ultimatelyshow"l ≤ ln x ∧ ln x ≤ u" .. qed
lemmas [simp del] = lb_ln.simps ub_ln.simps
lemma lb_lnD: "y ≤ ln x ∧ 0 < real_of_float x"if"lb_ln prec x = Some y" using lb_ln[OF that[symmetric]] by auto
lemma ub_lnD: "ln x ≤ y∧ 0 < real_of_float x"if"ub_ln prec x = Some y" using ub_ln[OF that[symmetric]] by auto
lemma ln_float_interval_eq_Some_conv: "ln_float_interval p x = Some y ⟷ lb_ln p (lower x) = Some (lower y) ∧ ub_ln p (upper x) = Some (upper y)" by transfer (auto simp: bind_eq_Some_conv)
lemma ln_float_interval: "ln ` set_of (real_interval x) ⊆ set_of (real_interval y)" if"ln_float_interval p x = Some y" using that lb_ln[of "lower y" p "lower x"]
ub_ln[of "lower y" p "lower x"] apply (auto simp add: set_of_eq ln_float_interval_eq_Some_conv ln_le_cancel_iff) apply (meson less_le_trans ln_less_cancel_iff not_le) by (meson less_le_trans ln_less_cancel_iff not_le ub_lnD)
lemma ln_float_intervalI: "ln x ∈ set_of' (ln_float_interval p X)"if"x ∈🪙r X" using ln_float_interval[of p X] that by (auto simp: set_of'_def split: option.splits)
lemma ln_float_interval_eqI: "ln x ∈🪙r IVL"if"ln_float_interval p X = Some IVL""x ∈🪙r X" using ln_float_intervalI[of x X p] that by (auto simp: set_of'_def split: option.splits)
section‹Real power function›
definition bnds_powr :: "nat ==> float ==> float ==> float ==> float ==> (float × float) option"where "bnds_powr prec l1 u1 l2 u2 = ( if l1 = 0 ∧ u1 = 0 then Some (0, 0) else if l1 = 0 ∧ l2 ≥ 1 then let uln = the (ub_ln prec u1) in Some (0, ub_exp prec (float_round_up prec (uln * (if uln ≥ 0 then u2 else l2)))) else if l1 ≤ 0 then None else Some (map_bnds lb_exp ub_exp prec (bnds_mult prec (the (lb_ln prec l1)) (the (ub_ln prec u1)) l2 u2)))"
lemma mono_exp_real: "mono (exp :: real ==> real)" by (auto simp: mono_def)
lemma bnds_powr: assumes lu: "Some (l, u) = bnds_powr prec l1 u1 l2 u2" assumes x: "x ∈ {real_of_float l1..real_of_float u1}" assumes y: "y ∈ {real_of_float l2..real_of_float u2}" shows"x powr y ∈ {real_of_float l..real_of_float u}" proof -
consider "l1 = 0""u1 = 0" | "l1 = 0""u1 ≠ 0""l2 ≥ 1" | "l1 ≤ 0""¬(l1 = 0 ∧ (u1 = 0 ∨ l2 ≥ 1))" | "l1 > 0"by force thus ?thesis proof cases assume"l1 = 0""u1 = 0" with x lu show ?thesis by (auto simp: bnds_powr_def) next assume A: "l1 = 0""u1 ≠ 0""l2 ≥ 1"
define uln where"uln = the (ub_ln prec u1)" show ?thesis proof (cases "x = 0") case False with A x y have"x powr y = exp (ln x * y)"by (simp add: powr_def) also { from A x False have"ln x ≤ ln (real_of_float u1)"by simp alsofrom ub_ln_lb_ln_bounds[of u1 prec] A y x False have"ln (real_of_float u1) ≤ real_of_float uln"by (simp add: uln_def del: lb_ln.simps) alsofrom A x y have"… * y ≤ real_of_float uln * (if uln ≥ 0 then u2 else l2)" by (auto intro: mult_left_mono mult_left_mono_neg) alsohave"…≤ real_of_float (float_round_up prec (uln * (if uln ≥ 0 then u2 else l2)))" by (simp add: float_round_up_le) finallyhave"ln x * y ≤…"using A y by - simp
} alsohave"exp (real_of_float (float_round_up prec (uln * (if uln ≥ 0 then u2 else l2)))) ≤ real_of_float (ub_exp prec (float_round_up prec (uln * (if uln ≥ 0 then u2 else l2))))" using exp_boundaries by simp finallyshow ?thesis using A x y lu by (simp add: bnds_powr_def uln_def Let_def del: lb_ln.simps ub_ln.simps) qed (insert x y lu A, simp_all add: bnds_powr_def Let_def ub_exp_nonneg
del: lb_ln.simps ub_ln.simps) next assume"l1 ≤ 0""¬(l1 = 0 ∧ (u1 = 0 ∨ l2 ≥ 1))" with lu show ?thesis by (simp add: bnds_powr_def split: if_split_asm) next assume l1: "l1 > 0" obtain lm um where lmum: "(lm, um) = bnds_mult prec (the (lb_ln prec l1)) (the (ub_ln prec u1)) l2 u2" by (cases "bnds_mult prec (the (lb_ln prec l1)) (the (ub_ln prec u1)) l2 u2") simp with l1 have"(l, u) = map_bnds lb_exp ub_exp prec (lm, um)" using lu by (simp add: bnds_powr_def del: lb_ln.simps ub_ln.simps split: if_split_asm) hence"exp (ln x * y) ∈ {real_of_float l..real_of_float u}" proof (rule map_bnds[OF _ mono_exp_real], goal_cases) case 1 let ?lln = "the (lb_ln prec l1)"and ?uln = "the (ub_ln prec u1)" from ub_ln_lb_ln_bounds[of l1 prec] ub_ln_lb_ln_bounds[of u1 prec] x l1 have"real_of_float ?lln ≤ ln (real_of_float l1) ∧ ln (real_of_float u1) ≤ real_of_float ?uln" by (auto simp del: lb_ln.simps ub_ln.simps) moreoverfrom l1 x have"ln (real_of_float l1) ≤ ln x ∧ ln x ≤ ln (real_of_float u1)" by auto ultimatelyhave ln: "real_of_float ?lln ≤ ln x ∧ ln x ≤ real_of_float ?uln"by simp from lmum show ?case by (rule bnds_mult) (insert y ln, simp_all) qed (insert exp_boundaries[of lm prec] exp_boundaries[of um prec], simp_all) with x l1 show ?thesis by (simp add: powr_def mult_ac) qed qed
lemma powr_float_interval: "{x powr y | x y. x ∈ set_of (real_interval X) ∧ y ∈ set_of (real_interval Y)} ⊆ set_of (real_interval R)" if"powr_float_interval prec X Y = Some R" using that by transfer (auto dest!: bnds_powr[OF sym])
lemma powr_float_intervalI: "x powr y ∈ set_of' (powr_float_interval p X Y)" if"x ∈🪙r X""y ∈🪙r Y" using powr_float_interval[of p X Y] that by (auto simp: set_of'_def split: option.splits)
lemma powr_float_interval_eqI: "x powr y ∈🪙r IVL" if"powr_float_interval p X Y = Some IVL""x ∈🪙r X""y ∈🪙r Y" using powr_float_intervalI[of x X y Y p] that by (auto simp: set_of'_def split: option.splits)
end
end
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.143Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.