| namespace lm { | |
| namespace ngram { | |
| /* Suppose "foo bar" appears with zero backoff but there is no trigram | |
| * beginning with these words. Then, when scoring "foo bar", the model could | |
| * return out_state containing "bar" or even null context if "bar" also has no | |
| * backoff and is never followed by another word. Then the backoff is set to | |
| * kNoExtensionBackoff. If the n-gram might be extended, then out_state must | |
| * contain the full n-gram, in which case kExtensionBackoff is set. In any | |
| * case, if an n-gram has non-zero backoff, the full state is returned so | |
| * backoff can be properly charged. | |
| * These differ only in sign bit because the backoff is in fact zero in either | |
| * case. | |
| */ | |
| const float kNoExtensionBackoff = -0.0; | |
| const float kExtensionBackoff = 0.0; | |
| const uint64_t kNoExtensionQuant = 0; | |
| const uint64_t kExtensionQuant = 1; | |
| inline void SetExtension(float &backoff) { | |
| if (backoff == kNoExtensionBackoff) backoff = kExtensionBackoff; | |
| } | |
| // This compiles down nicely. | |
| inline bool HasExtension(const float &backoff) { | |
| typedef union { float f; uint32_t i; } UnionValue; | |
| UnionValue compare, interpret; | |
| compare.f = kNoExtensionBackoff; | |
| interpret.f = backoff; | |
| return compare.i != interpret.i; | |
| } | |
| } // namespace ngram | |
| } // namespace lm | |