@@ -87,28 +87,35 @@ public byte[] Compress(ReadOnlySpan<double> values)
8787 trailingZeros = 0 ;
8888 }
8989
90- if ( prevLeadingZeros >= 0 && leadingZeros >= prevLeadingZeros && trailingZeros >= prevTrailingZeros )
90+ // Check if we can reuse previous control block for better compression
91+ // The current XOR must fit within the previous control block window
92+ int prevBlockSize = 64 - prevLeadingZeros - prevTrailingZeros ;
93+ bool canReusePrevBlock = prevLeadingZeros >= 0 &&
94+ leadingZeros >= prevLeadingZeros &&
95+ trailingZeros >= prevTrailingZeros &&
96+ prevBlockSize > 0 ;
97+
98+ if ( canReusePrevBlock )
9199 {
92- // Same or more leading/trailing zeros: write '0' + meaningful bits
100+ // '10' path: reuse previous control block
93101 writer . WriteBit ( false ) ;
94102
95- // Use previous control block
96- int blockSize = 64 - prevLeadingZeros - prevTrailingZeros ;
103+ // Write meaningful bits using previous control block size
97104 ulong meaningfulValue = ( xor >> prevTrailingZeros ) ;
98- if ( blockSize < 64 )
105+ if ( prevBlockSize < 64 )
99106 {
100- meaningfulValue &= ( 1UL << blockSize ) - 1 ;
107+ meaningfulValue &= ( 1UL << prevBlockSize ) - 1 ;
101108 }
102- writer . WriteBits ( meaningfulValue , blockSize ) ;
109+ writer . WriteBits ( meaningfulValue , prevBlockSize ) ;
110+ // Note: do NOT update prevLeadingZeros/prevTrailingZeros
103111 }
104112 else
105113 {
106- // Different leading/trailing zeros : write '1' + control block + meaningful bits
114+ // '11' path : write new control block
107115 writer . WriteBit ( true ) ;
108116
109- // Write control block: 5 bits for leading zeros, 6 bits for meaningful bits length
110- // Note: 6 bits can represent 0-63, so we store (meaningfulBits - 1) to represent 1-64
111- writer . WriteBits ( ( ulong ) leadingZeros , 5 ) ;
117+ // Write control block: 6 bits for leading zeros (0-63), 6 bits for meaningful bits length (1-64 stored as 0-63)
118+ writer . WriteBits ( ( ulong ) leadingZeros , 6 ) ;
112119 writer . WriteBits ( ( ulong ) ( meaningfulBits - 1 ) , 6 ) ;
113120
114121 // Write meaningful bits
@@ -177,11 +184,12 @@ public double[] Decompress(ReadOnlySpan<byte> compressed, int count)
177184 int blockSize = 64 - prevLeadingZeros - prevTrailingZeros ;
178185 ulong meaningfulValue = reader . ReadBits ( blockSize ) ;
179186 xor = meaningfulValue << prevTrailingZeros ;
187+ // Note: do NOT update prevLeadingZeros/prevTrailingZeros
180188 }
181189 else
182190 {
183191 // '11' -> new control block
184- int leadingZeros = ( int ) reader . ReadBits ( 5 ) ;
192+ int leadingZeros = ( int ) reader . ReadBits ( 6 ) ; // 6 bits for leading zeros (0-63)
185193 int meaningfulBits = ( int ) reader . ReadBits ( 6 ) + 1 ; // Add 1 to get 1-64 range
186194 int trailingZeros = 64 - leadingZeros - meaningfulBits ;
187195
0 commit comments