@@ -717,6 +717,35 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
717
717
}
718
718
}
719
719
720
+ const FRACTIONAL_BITS : u32 = 3 ;
721
+ const FRACTIONAL_BITMASK : u64 = ( 1 << FRACTIONAL_BITS ) - 1 ;
722
+ const LOG2_FRACTIONAL_PART : [ f64 ; 1 << FRACTIONAL_BITS ] =
723
+ [ 0.0 , 0.17 , 0.32 , 0.46 , 0.58 , 0.70 , 0.81 , 0.91 ] ;
724
+ const LOG2_10 : f64 = 3.32 ;
725
+
726
+ fn log10_approx ( numerator : u64 , denominator : u64 ) -> f64 {
727
+ ( log2_approx ( numerator) - log2_approx ( denominator) ) / LOG2_10
728
+ }
729
+
730
+ #[ inline]
731
+ fn log2_approx ( x : u64 ) -> f64 {
732
+ let leading_zeros = x. leading_zeros ( ) ;
733
+ let integer_part = ( 63 - leading_zeros) as f64 ;
734
+ let fractional_part = LOG2_FRACTIONAL_PART [
735
+ ( ( ( x << leading_zeros) >> ( 63 - FRACTIONAL_BITS ) ) & FRACTIONAL_BITMASK ) as usize
736
+ ] ;
737
+ integer_part + fractional_part
738
+ }
739
+
740
+ fn log10_approx_without_fractional ( numerator : u64 , denominator : u64 ) -> f64 {
741
+ ( log2_approx_without_fractional ( numerator) - log2_approx_without_fractional ( denominator) ) / LOG2_10
742
+ }
743
+
744
+ #[ inline]
745
+ fn log2_approx_without_fractional ( x : u64 ) -> f64 {
746
+ ( 63 - x. leading_zeros ( ) ) as f64
747
+ }
748
+
720
749
impl < G : Deref < Target = NetworkGraph > , T : Time > Score for ProbabilisticScorerUsingTime < G , T > {
721
750
fn channel_penalty_msat (
722
751
& self , short_channel_id : u64 , amount_msat : u64 , capacity_msat : u64 , source : & NodeId ,
@@ -737,8 +766,8 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
737
766
Probability :: Zero => u64:: max_value ( ) ,
738
767
Probability :: One => 0 ,
739
768
Probability :: Ratio { numerator, denominator } => {
740
- let success_probability = numerator as f64 / denominator as f64 ;
741
- ( -( success_probability . log10 ( ) ) * liquidity_penalty_multiplier_msat as f64 ) as u64
769
+ let log_success_probability = log10_approx ( numerator, denominator) ;
770
+ ( -log_success_probability * liquidity_penalty_multiplier_msat as f64 ) as u64
742
771
} ,
743
772
}
744
773
}
@@ -1737,43 +1766,43 @@ mod tests {
1737
1766
let target = target_node_id ( ) ;
1738
1767
1739
1768
assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1740
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1769
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_012 ) ;
1741
1770
1742
1771
scorer. payment_path_failed ( & payment_path_for_amount ( 768 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
1743
1772
scorer. payment_path_failed ( & payment_path_for_amount ( 128 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 43 ) ;
1744
1773
1745
1774
assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 0 ) ;
1746
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 92 ) ;
1747
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_424 ) ;
1775
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 96 ) ;
1776
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_427 ) ;
1748
1777
assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1749
1778
1750
1779
SinceEpoch :: advance ( Duration :: from_secs ( 9 ) ) ;
1751
1780
assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 0 ) ;
1752
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 92 ) ;
1753
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_424 ) ;
1781
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 96 ) ;
1782
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_427 ) ;
1754
1783
assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1755
1784
1756
1785
SinceEpoch :: advance ( Duration :: from_secs ( 1 ) ) ;
1757
1786
assert_eq ! ( scorer. channel_penalty_msat( 42 , 64 , 1_024 , & source, & target) , 0 ) ;
1758
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 34 ) ;
1759
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , 1_812 ) ;
1787
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 36 ) ;
1788
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , 1_807 ) ;
1760
1789
assert_eq ! ( scorer. channel_penalty_msat( 42 , 960 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1761
1790
1762
1791
// Fully decay liquidity lower bound.
1763
1792
SinceEpoch :: advance ( Duration :: from_secs ( 10 * 7 ) ) ;
1764
1793
assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1765
1794
assert_eq ! ( scorer. channel_penalty_msat( 42 , 1 , 1_024 , & source, & target) , 0 ) ;
1766
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_023 , 1_024 , & source, & target) , 2_709 ) ;
1767
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1795
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_023 , 1_024 , & source, & target) , 2_710 ) ;
1796
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_012 ) ;
1768
1797
1769
1798
// Fully decay liquidity upper bound.
1770
1799
SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1771
1800
assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1772
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1801
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_012 ) ;
1773
1802
1774
1803
SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1775
1804
assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1776
- assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1805
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_012 ) ;
1777
1806
}
1778
1807
1779
1808
#[ test]
@@ -1899,3 +1928,38 @@ mod tests {
1899
1928
assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , 500 , 1_000 , & source, & target) , 367 ) ;
1900
1929
}
1901
1930
}
1931
+
1932
+ #[ cfg( all( test, feature = "unstable" , not( feature = "no-std" ) ) ) ]
1933
+ mod benches {
1934
+ use super :: * ;
1935
+
1936
+ use test:: black_box;
1937
+ use test:: Bencher ;
1938
+
1939
+ #[ bench]
1940
+ fn log10_bench ( bench : & mut Bencher ) {
1941
+ bench. iter ( || {
1942
+ for i in 1 ..85_184 {
1943
+ black_box ( ( i as f64 / 85_184 as f64 ) . log10 ( ) ) ;
1944
+ }
1945
+ } ) ;
1946
+ }
1947
+
1948
+ #[ bench]
1949
+ fn log10_approx_bench ( bench : & mut Bencher ) {
1950
+ bench. iter ( || {
1951
+ for i in 1 ..85_184 {
1952
+ black_box ( log10_approx ( i, 85_184 ) ) ;
1953
+ }
1954
+ } ) ;
1955
+ }
1956
+
1957
+ #[ bench]
1958
+ fn log10_approx_without_fractional_bench ( bench : & mut Bencher ) {
1959
+ bench. iter ( || {
1960
+ for i in 1 ..85_184 {
1961
+ black_box ( log10_approx_without_fractional ( i, 85_184 ) ) ;
1962
+ }
1963
+ } ) ;
1964
+ }
1965
+ }
0 commit comments