Library Coq.Numbers.NatInt.NZLog
Base-2 Logarithm
Interface of a log2 function, then its specification on naturals
Module Type Log2 (Import A : Typ).
Parameter Inline log2 : t -> t.
End Log2.
Module Type NZLog2Spec (A : NZOrdAxiomsSig')(B : Pow' A)(C : Log2 A).
Import A B C.
Axiom log2_spec : forall a, 0<a -> 2^(log2 a) <= a < 2^(S (log2 a)).
Axiom log2_nonpos : forall a, a<=0 -> log2 a == 0.
End NZLog2Spec.
Module Type NZLog2 (A : NZOrdAxiomsSig)(B : Pow A) := Log2 A <+ NZLog2Spec A B.
Derived properties of logarithm
Module Type NZLog2Prop
(Import A : NZOrdAxiomsSig')
(Import B : NZPow' A)
(Import C : NZLog2 A B)
(Import D : NZMulOrderProp A)
(Import E : NZPowProp A B D).
log2 is always non-negative
A tactic for proving positivity and non-negativity
Ltac order_pos :=
((apply add_pos_pos || apply add_nonneg_nonneg ||
apply mul_pos_pos || apply mul_nonneg_nonneg ||
apply pow_nonneg || apply pow_pos_nonneg ||
apply log2_nonneg || apply (le_le_succ_r 0));
order_pos)
|| order'.
The spec of log2 indeed determines it
Hence log2 is a morphism.
An alternate specification
Lemma log2_spec_alt : forall a, 0<a -> exists r,
a == 2^(log2 a) + r /\ 0 <= r < 2^(log2 a).
Lemma log2_unique' : forall a b c, 0<=b -> 0<=c<2^b ->
a == 2^b + c -> log2 a == b.
log2 is exact on powers of 2
log2 and predecessors of powers of 2
log2 and basic constants
log2 n is strictly positive for 1<n
Said otherwise, log2 is null only below 1
log2 is a monotone function (but not a strict one)
No reverse result for <=, consider for instance log2 3 <= log2 2
When left side is a power of 2, we have an equivalence for <=
When right side is a square, we have an equivalence for <
Comparing log2 and identity
Log2 and multiplication.
Due to rounding error, we don't have the usual
log2 (a*b) = log2 a + log2 b but we may be off by 1 at most
Lemma log2_mul_below : forall a b, 0<a -> 0<b ->
log2 a + log2 b <= log2 (a*b).
Lemma log2_mul_above : forall a b, 0<=a -> 0<=b ->
log2 (a*b) <= log2 a + log2 b + 1.
And we can't find better approximations in general.
At least, we get back the usual equation when we multiply by 2 (or 2^k)
- The lower bound is exact for powers of 2.
- Concerning the upper bound, for any c>1, take a=b=2^c-1, then log2 (a*b) = c+c -1 while (log2 a) = (log2 b) = c-1
Lemma log2_mul_pow2 : forall a b, 0<a -> 0<=b -> log2 (a*2^b) == b + log2 a.
Lemma log2_double : forall a, 0<a -> log2 (2*a) == S (log2 a).
Two numbers with same log2 cannot be far away.
Log2 and successor :
- the log2 function climbs by at most 1 at a time
- otherwise it stays at the same value
- the +1 steps occur for powers of two
Lemma log2_succ_le : forall a, log2 (S a) <= S (log2 a).
Lemma log2_succ_or : forall a,
log2 (S a) == S (log2 a) \/ log2 (S a) == log2 a.
Lemma log2_eq_succ_is_pow2 : forall a,
log2 (S a) == S (log2 a) -> exists b, S a == 2^b.
Lemma log2_eq_succ_iff_pow2 : forall a, 0<a ->
(log2 (S a) == S (log2 a) <-> exists b, S a == 2^b).
Lemma log2_succ_double : forall a, 0<a -> log2 (2*a+1) == S (log2 a).
Log2 and addition
The sum of two log2 is less than twice the log2 of the sum.
The large inequality is obvious thanks to monotonicity.
The strict one requires some more work. This is almost
a convexity inequality for points 2a, 2b and their middle a+b :
ideally, we would have 2*log(a+b) >= log(2a)+log(2b) = 2+log a+log b.
Here, we cannot do better: consider for instance a=2 b=4, then 1+2<2*2
Lemma add_log2_lt : forall a b, 0<a -> 0<b ->
log2 a + log2 b < 2 * log2 (a+b).
End NZLog2Prop.
Module NZLog2UpProp
(Import A : NZDecOrdAxiomsSig')
(Import B : NZPow' A)
(Import C : NZLog2 A B)
(Import D : NZMulOrderProp A)
(Import E : NZPowProp A B D)
(Import F : NZLog2Prop A B C D E).
log2_up : a binary logarithm that rounds up instead of down
Definition log2_up a :=
match compare 1 a with
| Lt => S (log2 (P a))
| _ => 0
end.
Lemma log2_up_eqn0 : forall a, a<=1 -> log2_up a == 0.
Lemma log2_up_eqn : forall a, 1<a -> log2_up a == S (log2 (P a)).
Lemma log2_up_spec : forall a, 1<a ->
2^(P (log2_up a)) < a <= 2^(log2_up a).
Lemma log2_up_nonpos : forall a, a<=0 -> log2_up a == 0.
Instance log2_up_wd : Proper (eq==>eq) log2_up.
log2_up is always non-negative
The spec of log2_up indeed determines it
log2_up is exact on powers of 2
log2_up and successors of powers of 2
Basic constants
Links between log2 and log2_up
Lemma le_log2_log2_up : forall a, log2 a <= log2_up a.
Lemma le_log2_up_succ_log2 : forall a, log2_up a <= S (log2 a).
Lemma log2_log2_up_spec : forall a, 0<a ->
2^log2 a <= a <= 2^log2_up a.
Lemma log2_log2_up_exact :
forall a, 0<a -> (log2 a == log2_up a <-> exists b, a == 2^b).
log2_up n is strictly positive for 1<n
Said otherwise, log2_up is null only below 1
log2_up is a monotone function (but not a strict one)
No reverse result for <=, consider for instance log2_up 4 <= log2_up 3
When left side is a power of 2, we have an equivalence for <
When right side is a square, we have an equivalence for <=
Comparing log2_up and identity
Lemma log2_up_lt_lin : forall a, 0<a -> log2_up a < a.
Lemma log2_up_le_lin : forall a, 0<=a -> log2_up a <= a.
log2_up and multiplication.
Due to rounding error, we don't have the usual
log2_up (a*b) = log2_up a + log2_up b but we may be off by 1 at most
Lemma log2_up_mul_above : forall a b, 0<=a -> 0<=b ->
log2_up (a*b) <= log2_up a + log2_up b.
Lemma log2_up_mul_below : forall a b, 0<a -> 0<b ->
log2_up a + log2_up b <= S (log2_up (a*b)).
And we can't find better approximations in general.
At least, we get back the usual equation when we multiply by 2 (or 2^k)
- The upper bound is exact for powers of 2.
- Concerning the lower bound, for any c>1, take a=b=2^c+1, then log2_up (a*b) = c+c +1 while (log2_up a) = (log2_up b) = c+1
Lemma log2_up_mul_pow2 : forall a b, 0<a -> 0<=b ->
log2_up (a*2^b) == b + log2_up a.
Lemma log2_up_double : forall a, 0<a -> log2_up (2*a) == S (log2_up a).
Two numbers with same log2_up cannot be far away.
log2_up and successor :
- the log2_up function climbs by at most 1 at a time
- otherwise it stays at the same value
- the +1 steps occur after powers of two
Lemma log2_up_succ_le : forall a, log2_up (S a) <= S (log2_up a).
Lemma log2_up_succ_or : forall a,
log2_up (S a) == S (log2_up a) \/ log2_up (S a) == log2_up a.
Lemma log2_up_eq_succ_is_pow2 : forall a,
log2_up (S a) == S (log2_up a) -> exists b, a == 2^b.
Lemma log2_up_eq_succ_iff_pow2 : forall a, 0<a ->
(log2_up (S a) == S (log2_up a) <-> exists b, a == 2^b).
Lemma log2_up_succ_double : forall a, 0<a ->
log2_up (2*a+1) == 2 + log2 a.
log2_up and addition
The sum of two log2_up is less than twice the log2_up of the sum.
The large inequality is obvious thanks to monotonicity.
The strict one requires some more work. This is almost
a convexity inequality for points 2a, 2b and their middle a+b :
ideally, we would have 2*log(a+b) >= log(2a)+log(2b) = 2+log a+log b.
Here, we cannot do better: consider for instance a=3 b=5, then 2+3<2*3