source: josm/trunk/src/org/tukaani/xz/lzma/LZMAEncoder.java@ 15147

Last change on this file since 15147 was 13350, checked in by stoecker, 7 years ago

see #15816 - add XZ support

File size: 24.3 KB
Line 
1/*
2 * LZMAEncoder
3 *
4 * Authors: Lasse Collin <lasse.collin@tukaani.org>
5 * Igor Pavlov <http://7-zip.org/>
6 *
7 * This file has been put into the public domain.
8 * You can do whatever you want with this file.
9 */
10
11package org.tukaani.xz.lzma;
12
13import java.io.IOException;
14import org.tukaani.xz.ArrayCache;
15import org.tukaani.xz.lz.LZEncoder;
16import org.tukaani.xz.lz.Matches;
17import org.tukaani.xz.rangecoder.RangeEncoder;
18
19public abstract class LZMAEncoder extends LZMACoder {
20 public static final int MODE_FAST = 1;
21 public static final int MODE_NORMAL = 2;
22
23 /**
24 * LZMA2 chunk is considered full when its uncompressed size exceeds
25 * <code>LZMA2_UNCOMPRESSED_LIMIT</code>.
26 * <p>
27 * A compressed LZMA2 chunk can hold 2 MiB of uncompressed data.
28 * A single LZMA symbol may indicate up to MATCH_LEN_MAX bytes
29 * of data, so the LZMA2 chunk is considered full when there is
30 * less space than MATCH_LEN_MAX bytes.
31 */
32 private static final int LZMA2_UNCOMPRESSED_LIMIT
33 = (2 << 20) - MATCH_LEN_MAX;
34
35 /**
36 * LZMA2 chunk is considered full when its compressed size exceeds
37 * <code>LZMA2_COMPRESSED_LIMIT</code>.
38 * <p>
39 * The maximum compressed size of a LZMA2 chunk is 64 KiB.
40 * A single LZMA symbol might use 20 bytes of space even though
41 * it usually takes just one byte or so. Two more bytes are needed
42 * for LZMA2 uncompressed chunks (see LZMA2OutputStream.writeChunk).
43 * Leave a little safety margin and use 26 bytes.
44 */
45 private static final int LZMA2_COMPRESSED_LIMIT = (64 << 10) - 26;
46
47 private static final int DIST_PRICE_UPDATE_INTERVAL = FULL_DISTANCES;
48 private static final int ALIGN_PRICE_UPDATE_INTERVAL = ALIGN_SIZE;
49
50 private final RangeEncoder rc;
51 final LZEncoder lz;
52 final LiteralEncoder literalEncoder;
53 final LengthEncoder matchLenEncoder;
54 final LengthEncoder repLenEncoder;
55 final int niceLen;
56
57 private int distPriceCount = 0;
58 private int alignPriceCount = 0;
59
60 private final int distSlotPricesSize;
61 private final int[][] distSlotPrices;
62 private final int[][] fullDistPrices
63 = new int[DIST_STATES][FULL_DISTANCES];
64 private final int[] alignPrices = new int[ALIGN_SIZE];
65
66 int back = 0;
67 int readAhead = -1;
68 private int uncompressedSize = 0;
69
70 public static int getMemoryUsage(int mode, int dictSize,
71 int extraSizeBefore, int mf) {
72 int m = 80;
73
74 switch (mode) {
75 case MODE_FAST:
76 m += LZMAEncoderFast.getMemoryUsage(
77 dictSize, extraSizeBefore, mf);
78 break;
79
80 case MODE_NORMAL:
81 m += LZMAEncoderNormal.getMemoryUsage(
82 dictSize, extraSizeBefore, mf);
83 break;
84
85 default:
86 throw new IllegalArgumentException();
87 }
88
89 return m;
90 }
91
92 public static LZMAEncoder getInstance(
93 RangeEncoder rc, int lc, int lp, int pb, int mode,
94 int dictSize, int extraSizeBefore,
95 int niceLen, int mf, int depthLimit,
96 ArrayCache arrayCache) {
97 switch (mode) {
98 case MODE_FAST:
99 return new LZMAEncoderFast(rc, lc, lp, pb,
100 dictSize, extraSizeBefore,
101 niceLen, mf, depthLimit,
102 arrayCache);
103
104 case MODE_NORMAL:
105 return new LZMAEncoderNormal(rc, lc, lp, pb,
106 dictSize, extraSizeBefore,
107 niceLen, mf, depthLimit,
108 arrayCache);
109 }
110
111 throw new IllegalArgumentException();
112 }
113
114 public void putArraysToCache(ArrayCache arrayCache) {
115 lz.putArraysToCache(arrayCache);
116 }
117
118 /**
119 * Gets an integer [0, 63] matching the highest two bits of an integer.
120 * This is like bit scan reverse (BSR) on x86 except that this also
121 * cares about the second highest bit.
122 */
123 public static int getDistSlot(int dist) {
124 if (dist <= DIST_MODEL_START && dist >= 0)
125 return dist;
126
127 int n = dist;
128 int i = 31;
129
130 if ((n & 0xFFFF0000) == 0) {
131 n <<= 16;
132 i = 15;
133 }
134
135 if ((n & 0xFF000000) == 0) {
136 n <<= 8;
137 i -= 8;
138 }
139
140 if ((n & 0xF0000000) == 0) {
141 n <<= 4;
142 i -= 4;
143 }
144
145 if ((n & 0xC0000000) == 0) {
146 n <<= 2;
147 i -= 2;
148 }
149
150 if ((n & 0x80000000) == 0)
151 --i;
152
153 return (i << 1) + ((dist >>> (i - 1)) & 1);
154 }
155
156 /**
157 * Gets the next LZMA symbol.
158 * <p>
159 * There are three types of symbols: literal (a single byte),
160 * repeated match, and normal match. The symbol is indicated
161 * by the return value and by the variable <code>back</code>.
162 * <p>
163 * Literal: <code>back == -1</code> and return value is <code>1</code>.
164 * The literal itself needs to be read from <code>lz</code> separately.
165 * <p>
166 * Repeated match: <code>back</code> is in the range [0, 3] and
167 * the return value is the length of the repeated match.
168 * <p>
169 * Normal match: <code>back - REPS<code> (<code>back - 4</code>)
170 * is the distance of the match and the return value is the length
171 * of the match.
172 */
173 abstract int getNextSymbol();
174
175 LZMAEncoder(RangeEncoder rc, LZEncoder lz,
176 int lc, int lp, int pb, int dictSize, int niceLen) {
177 super(pb);
178 this.rc = rc;
179 this.lz = lz;
180 this.niceLen = niceLen;
181
182 literalEncoder = new LiteralEncoder(lc, lp);
183 matchLenEncoder = new LengthEncoder(pb, niceLen);
184 repLenEncoder = new LengthEncoder(pb, niceLen);
185
186 distSlotPricesSize = getDistSlot(dictSize - 1) + 1;
187 distSlotPrices = new int[DIST_STATES][distSlotPricesSize];
188
189 reset();
190 }
191
192 public LZEncoder getLZEncoder() {
193 return lz;
194 }
195
196 public void reset() {
197 super.reset();
198 literalEncoder.reset();
199 matchLenEncoder.reset();
200 repLenEncoder.reset();
201 distPriceCount = 0;
202 alignPriceCount = 0;
203
204 uncompressedSize += readAhead + 1;
205 readAhead = -1;
206 }
207
208 public int getUncompressedSize() {
209 return uncompressedSize;
210 }
211
212 public void resetUncompressedSize() {
213 uncompressedSize = 0;
214 }
215
216 /**
217 * Compress for LZMA1.
218 */
219 public void encodeForLZMA1() throws IOException {
220 if (!lz.isStarted() && !encodeInit())
221 return;
222
223 while (encodeSymbol()) {}
224 }
225
226 public void encodeLZMA1EndMarker() throws IOException {
227 // End of stream marker is encoded as a match with the maximum
228 // possible distance. The length is ignored by the decoder,
229 // but the minimum length has been used by the LZMA SDK.
230 //
231 // Distance is a 32-bit unsigned integer in LZMA.
232 // With Java's signed int, UINT32_MAX becomes -1.
233 int posState = (lz.getPos() - readAhead) & posMask;
234 rc.encodeBit(isMatch[state.get()], posState, 1);
235 rc.encodeBit(isRep, state.get(), 0);
236 encodeMatch(-1, MATCH_LEN_MIN, posState);
237 }
238
239 /**
240 * Compresses for LZMA2.
241 *
242 * @return true if the LZMA2 chunk became full, false otherwise
243 */
244 public boolean encodeForLZMA2() {
245 // LZMA2 uses RangeEncoderToBuffer so IOExceptions aren't possible.
246 try {
247 if (!lz.isStarted() && !encodeInit())
248 return false;
249
250 while (uncompressedSize <= LZMA2_UNCOMPRESSED_LIMIT
251 && rc.getPendingSize() <= LZMA2_COMPRESSED_LIMIT)
252 if (!encodeSymbol())
253 return false;
254 } catch (IOException e) {
255 throw new Error();
256 }
257
258 return true;
259 }
260
261 private boolean encodeInit() throws IOException {
262 assert readAhead == -1;
263 if (!lz.hasEnoughData(0))
264 return false;
265
266 // The first symbol must be a literal unless using
267 // a preset dictionary. This code isn't run if using
268 // a preset dictionary.
269 skip(1);
270 rc.encodeBit(isMatch[state.get()], 0, 0);
271 literalEncoder.encodeInit();
272
273 --readAhead;
274 assert readAhead == -1;
275
276 ++uncompressedSize;
277 assert uncompressedSize == 1;
278
279 return true;
280 }
281
282 private boolean encodeSymbol() throws IOException {
283 if (!lz.hasEnoughData(readAhead + 1))
284 return false;
285
286 int len = getNextSymbol();
287
288 assert readAhead >= 0;
289 int posState = (lz.getPos() - readAhead) & posMask;
290
291 if (back == -1) {
292 // Literal i.e. eight-bit byte
293 assert len == 1;
294 rc.encodeBit(isMatch[state.get()], posState, 0);
295 literalEncoder.encode();
296 } else {
297 // Some type of match
298 rc.encodeBit(isMatch[state.get()], posState, 1);
299 if (back < REPS) {
300 // Repeated match i.e. the same distance
301 // has been used earlier.
302 assert lz.getMatchLen(-readAhead, reps[back], len) == len;
303 rc.encodeBit(isRep, state.get(), 1);
304 encodeRepMatch(back, len, posState);
305 } else {
306 // Normal match
307 assert lz.getMatchLen(-readAhead, back - REPS, len) == len;
308 rc.encodeBit(isRep, state.get(), 0);
309 encodeMatch(back - REPS, len, posState);
310 }
311 }
312
313 readAhead -= len;
314 uncompressedSize += len;
315
316 return true;
317 }
318
319 private void encodeMatch(int dist, int len, int posState)
320 throws IOException {
321 state.updateMatch();
322 matchLenEncoder.encode(len, posState);
323
324 int distSlot = getDistSlot(dist);
325 rc.encodeBitTree(distSlots[getDistState(len)], distSlot);
326
327 if (distSlot >= DIST_MODEL_START) {
328 int footerBits = (distSlot >>> 1) - 1;
329 int base = (2 | (distSlot & 1)) << footerBits;
330 int distReduced = dist - base;
331
332 if (distSlot < DIST_MODEL_END) {
333 rc.encodeReverseBitTree(
334 distSpecial[distSlot - DIST_MODEL_START],
335 distReduced);
336 } else {
337 rc.encodeDirectBits(distReduced >>> ALIGN_BITS,
338 footerBits - ALIGN_BITS);
339 rc.encodeReverseBitTree(distAlign, distReduced & ALIGN_MASK);
340 --alignPriceCount;
341 }
342 }
343
344 reps[3] = reps[2];
345 reps[2] = reps[1];
346 reps[1] = reps[0];
347 reps[0] = dist;
348
349 --distPriceCount;
350 }
351
352 private void encodeRepMatch(int rep, int len, int posState)
353 throws IOException {
354 if (rep == 0) {
355 rc.encodeBit(isRep0, state.get(), 0);
356 rc.encodeBit(isRep0Long[state.get()], posState, len == 1 ? 0 : 1);
357 } else {
358 int dist = reps[rep];
359 rc.encodeBit(isRep0, state.get(), 1);
360
361 if (rep == 1) {
362 rc.encodeBit(isRep1, state.get(), 0);
363 } else {
364 rc.encodeBit(isRep1, state.get(), 1);
365 rc.encodeBit(isRep2, state.get(), rep - 2);
366
367 if (rep == 3)
368 reps[3] = reps[2];
369
370 reps[2] = reps[1];
371 }
372
373 reps[1] = reps[0];
374 reps[0] = dist;
375 }
376
377 if (len == 1) {
378 state.updateShortRep();
379 } else {
380 repLenEncoder.encode(len, posState);
381 state.updateLongRep();
382 }
383 }
384
385 Matches getMatches() {
386 ++readAhead;
387 Matches matches = lz.getMatches();
388 assert lz.verifyMatches(matches);
389 return matches;
390 }
391
392 void skip(int len) {
393 readAhead += len;
394 lz.skip(len);
395 }
396
397 int getAnyMatchPrice(State state, int posState) {
398 return RangeEncoder.getBitPrice(isMatch[state.get()][posState], 1);
399 }
400
401 int getNormalMatchPrice(int anyMatchPrice, State state) {
402 return anyMatchPrice
403 + RangeEncoder.getBitPrice(isRep[state.get()], 0);
404 }
405
406 int getAnyRepPrice(int anyMatchPrice, State state) {
407 return anyMatchPrice
408 + RangeEncoder.getBitPrice(isRep[state.get()], 1);
409 }
410
411 int getShortRepPrice(int anyRepPrice, State state, int posState) {
412 return anyRepPrice
413 + RangeEncoder.getBitPrice(isRep0[state.get()], 0)
414 + RangeEncoder.getBitPrice(isRep0Long[state.get()][posState],
415 0);
416 }
417
418 int getLongRepPrice(int anyRepPrice, int rep, State state, int posState) {
419 int price = anyRepPrice;
420
421 if (rep == 0) {
422 price += RangeEncoder.getBitPrice(isRep0[state.get()], 0)
423 + RangeEncoder.getBitPrice(
424 isRep0Long[state.get()][posState], 1);
425 } else {
426 price += RangeEncoder.getBitPrice(isRep0[state.get()], 1);
427
428 if (rep == 1)
429 price += RangeEncoder.getBitPrice(isRep1[state.get()], 0);
430 else
431 price += RangeEncoder.getBitPrice(isRep1[state.get()], 1)
432 + RangeEncoder.getBitPrice(isRep2[state.get()],
433 rep - 2);
434 }
435
436 return price;
437 }
438
439 int getLongRepAndLenPrice(int rep, int len, State state, int posState) {
440 int anyMatchPrice = getAnyMatchPrice(state, posState);
441 int anyRepPrice = getAnyRepPrice(anyMatchPrice, state);
442 int longRepPrice = getLongRepPrice(anyRepPrice, rep, state, posState);
443 return longRepPrice + repLenEncoder.getPrice(len, posState);
444 }
445
446 int getMatchAndLenPrice(int normalMatchPrice,
447 int dist, int len, int posState) {
448 int price = normalMatchPrice
449 + matchLenEncoder.getPrice(len, posState);
450 int distState = getDistState(len);
451
452 if (dist < FULL_DISTANCES) {
453 price += fullDistPrices[distState][dist];
454 } else {
455 // Note that distSlotPrices includes also
456 // the price of direct bits.
457 int distSlot = getDistSlot(dist);
458 price += distSlotPrices[distState][distSlot]
459 + alignPrices[dist & ALIGN_MASK];
460 }
461
462 return price;
463 }
464
465 private void updateDistPrices() {
466 distPriceCount = DIST_PRICE_UPDATE_INTERVAL;
467
468 for (int distState = 0; distState < DIST_STATES; ++distState) {
469 for (int distSlot = 0; distSlot < distSlotPricesSize; ++distSlot)
470 distSlotPrices[distState][distSlot]
471 = RangeEncoder.getBitTreePrice(
472 distSlots[distState], distSlot);
473
474 for (int distSlot = DIST_MODEL_END; distSlot < distSlotPricesSize;
475 ++distSlot) {
476 int count = (distSlot >>> 1) - 1 - ALIGN_BITS;
477 distSlotPrices[distState][distSlot]
478 += RangeEncoder.getDirectBitsPrice(count);
479 }
480
481 for (int dist = 0; dist < DIST_MODEL_START; ++dist)
482 fullDistPrices[distState][dist]
483 = distSlotPrices[distState][dist];
484 }
485
486 int dist = DIST_MODEL_START;
487 for (int distSlot = DIST_MODEL_START; distSlot < DIST_MODEL_END;
488 ++distSlot) {
489 int footerBits = (distSlot >>> 1) - 1;
490 int base = (2 | (distSlot & 1)) << footerBits;
491
492 int limit = distSpecial[distSlot - DIST_MODEL_START].length;
493 for (int i = 0; i < limit; ++i) {
494 int distReduced = dist - base;
495 int price = RangeEncoder.getReverseBitTreePrice(
496 distSpecial[distSlot - DIST_MODEL_START],
497 distReduced);
498
499 for (int distState = 0; distState < DIST_STATES; ++distState)
500 fullDistPrices[distState][dist]
501 = distSlotPrices[distState][distSlot] + price;
502
503 ++dist;
504 }
505 }
506
507 assert dist == FULL_DISTANCES;
508 }
509
510 private void updateAlignPrices() {
511 alignPriceCount = ALIGN_PRICE_UPDATE_INTERVAL;
512
513 for (int i = 0; i < ALIGN_SIZE; ++i)
514 alignPrices[i] = RangeEncoder.getReverseBitTreePrice(distAlign,
515 i);
516 }
517
518 /**
519 * Updates the lookup tables used for calculating match distance
520 * and length prices. The updating is skipped for performance reasons
521 * if the tables haven't changed much since the previous update.
522 */
523 void updatePrices() {
524 if (distPriceCount <= 0)
525 updateDistPrices();
526
527 if (alignPriceCount <= 0)
528 updateAlignPrices();
529
530 matchLenEncoder.updatePrices();
531 repLenEncoder.updatePrices();
532 }
533
534
535 class LiteralEncoder extends LiteralCoder {
536 private final LiteralSubencoder[] subencoders;
537
538 LiteralEncoder(int lc, int lp) {
539 super(lc, lp);
540
541 subencoders = new LiteralSubencoder[1 << (lc + lp)];
542 for (int i = 0; i < subencoders.length; ++i)
543 subencoders[i] = new LiteralSubencoder();
544 }
545
546 void reset() {
547 for (int i = 0; i < subencoders.length; ++i)
548 subencoders[i].reset();
549 }
550
551 void encodeInit() throws IOException {
552 // When encoding the first byte of the stream, there is
553 // no previous byte in the dictionary so the encode function
554 // wouldn't work.
555 assert readAhead >= 0;
556 subencoders[0].encode();
557 }
558
559 void encode() throws IOException {
560 assert readAhead >= 0;
561 int i = getSubcoderIndex(lz.getByte(1 + readAhead),
562 lz.getPos() - readAhead);
563 subencoders[i].encode();
564 }
565
566 int getPrice(int curByte, int matchByte,
567 int prevByte, int pos, State state) {
568 int price = RangeEncoder.getBitPrice(
569 isMatch[state.get()][pos & posMask], 0);
570
571 int i = getSubcoderIndex(prevByte, pos);
572 price += state.isLiteral()
573 ? subencoders[i].getNormalPrice(curByte)
574 : subencoders[i].getMatchedPrice(curByte, matchByte);
575
576 return price;
577 }
578
579 private class LiteralSubencoder extends LiteralSubcoder {
580 void encode() throws IOException {
581 int symbol = lz.getByte(readAhead) | 0x100;
582
583 if (state.isLiteral()) {
584 int subencoderIndex;
585 int bit;
586
587 do {
588 subencoderIndex = symbol >>> 8;
589 bit = (symbol >>> 7) & 1;
590 rc.encodeBit(probs, subencoderIndex, bit);
591 symbol <<= 1;
592 } while (symbol < 0x10000);
593
594 } else {
595 int matchByte = lz.getByte(reps[0] + 1 + readAhead);
596 int offset = 0x100;
597 int subencoderIndex;
598 int matchBit;
599 int bit;
600
601 do {
602 matchByte <<= 1;
603 matchBit = matchByte & offset;
604 subencoderIndex = offset + matchBit + (symbol >>> 8);
605 bit = (symbol >>> 7) & 1;
606 rc.encodeBit(probs, subencoderIndex, bit);
607 symbol <<= 1;
608 offset &= ~(matchByte ^ symbol);
609 } while (symbol < 0x10000);
610 }
611
612 state.updateLiteral();
613 }
614
615 int getNormalPrice(int symbol) {
616 int price = 0;
617 int subencoderIndex;
618 int bit;
619
620 symbol |= 0x100;
621
622 do {
623 subencoderIndex = symbol >>> 8;
624 bit = (symbol >>> 7) & 1;
625 price += RangeEncoder.getBitPrice(probs[subencoderIndex],
626 bit);
627 symbol <<= 1;
628 } while (symbol < (0x100 << 8));
629
630 return price;
631 }
632
633 int getMatchedPrice(int symbol, int matchByte) {
634 int price = 0;
635 int offset = 0x100;
636 int subencoderIndex;
637 int matchBit;
638 int bit;
639
640 symbol |= 0x100;
641
642 do {
643 matchByte <<= 1;
644 matchBit = matchByte & offset;
645 subencoderIndex = offset + matchBit + (symbol >>> 8);
646 bit = (symbol >>> 7) & 1;
647 price += RangeEncoder.getBitPrice(probs[subencoderIndex],
648 bit);
649 symbol <<= 1;
650 offset &= ~(matchByte ^ symbol);
651 } while (symbol < (0x100 << 8));
652
653 return price;
654 }
655 }
656 }
657
658
659 class LengthEncoder extends LengthCoder {
660 /**
661 * The prices are updated after at least
662 * <code>PRICE_UPDATE_INTERVAL</code> many lengths
663 * have been encoded with the same posState.
664 */
665 private static final int PRICE_UPDATE_INTERVAL = 32; // FIXME?
666
667 private final int[] counters;
668 private final int[][] prices;
669
670 LengthEncoder(int pb, int niceLen) {
671 int posStates = 1 << pb;
672 counters = new int[posStates];
673
674 // Always allocate at least LOW_SYMBOLS + MID_SYMBOLS because
675 // it makes updatePrices slightly simpler. The prices aren't
676 // usually needed anyway if niceLen < 18.
677 int lenSymbols = Math.max(niceLen - MATCH_LEN_MIN + 1,
678 LOW_SYMBOLS + MID_SYMBOLS);
679 prices = new int[posStates][lenSymbols];
680 }
681
682 void reset() {
683 super.reset();
684
685 // Reset counters to zero to force price update before
686 // the prices are needed.
687 for (int i = 0; i < counters.length; ++i)
688 counters[i] = 0;
689 }
690
691 void encode(int len, int posState) throws IOException {
692 len -= MATCH_LEN_MIN;
693
694 if (len < LOW_SYMBOLS) {
695 rc.encodeBit(choice, 0, 0);
696 rc.encodeBitTree(low[posState], len);
697 } else {
698 rc.encodeBit(choice, 0, 1);
699 len -= LOW_SYMBOLS;
700
701 if (len < MID_SYMBOLS) {
702 rc.encodeBit(choice, 1, 0);
703 rc.encodeBitTree(mid[posState], len);
704 } else {
705 rc.encodeBit(choice, 1, 1);
706 rc.encodeBitTree(high, len - MID_SYMBOLS);
707 }
708 }
709
710 --counters[posState];
711 }
712
713 int getPrice(int len, int posState) {
714 return prices[posState][len - MATCH_LEN_MIN];
715 }
716
717 void updatePrices() {
718 for (int posState = 0; posState < counters.length; ++posState) {
719 if (counters[posState] <= 0) {
720 counters[posState] = PRICE_UPDATE_INTERVAL;
721 updatePrices(posState);
722 }
723 }
724 }
725
726 private void updatePrices(int posState) {
727 int choice0Price = RangeEncoder.getBitPrice(choice[0], 0);
728
729 int i = 0;
730 for (; i < LOW_SYMBOLS; ++i)
731 prices[posState][i] = choice0Price
732 + RangeEncoder.getBitTreePrice(low[posState], i);
733
734 choice0Price = RangeEncoder.getBitPrice(choice[0], 1);
735 int choice1Price = RangeEncoder.getBitPrice(choice[1], 0);
736
737 for (; i < LOW_SYMBOLS + MID_SYMBOLS; ++i)
738 prices[posState][i] = choice0Price + choice1Price
739 + RangeEncoder.getBitTreePrice(mid[posState],
740 i - LOW_SYMBOLS);
741
742 choice1Price = RangeEncoder.getBitPrice(choice[1], 1);
743
744 for (; i < prices[posState].length; ++i)
745 prices[posState][i] = choice0Price + choice1Price
746 + RangeEncoder.getBitTreePrice(high, i - LOW_SYMBOLS
747 - MID_SYMBOLS);
748 }
749 }
750}
Note: See TracBrowser for help on using the repository browser.