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