-
Notifications
You must be signed in to change notification settings - Fork 37
/
condition.go
166 lines (146 loc) · 5.25 KB
/
condition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package apd
import (
"errors"
"fmt"
"strings"
)
// Condition holds condition flags.
type Condition uint32
const (
// SystemOverflow is raised when an exponent is greater than MaxExponent.
SystemOverflow Condition = 1 << iota
// SystemUnderflow is raised when an exponent is less than MinExponent.
SystemUnderflow
// Overflow is raised when the exponent of a result is too large to be
// represented.
Overflow
// Underflow is raised when a result is both subnormal and inexact.
Underflow
// Inexact is raised when a result is not exact (one or more non-zero
// coefficient digits were discarded during rounding).
Inexact
// Subnormal is raised when a result is subnormal (its adjusted exponent is
// less than Emin), before any rounding.
Subnormal
// Rounded is raised when a result has been rounded (that is, some zero or
// non-zero coefficient digits were discarded).
Rounded
// DivisionUndefined is raised when both division operands are 0.
DivisionUndefined
// DivisionByZero is raised when a non-zero dividend is divided by zero.
DivisionByZero
// DivisionImpossible is raised when integer division cannot be exactly
// represented with the given precision.
DivisionImpossible
// InvalidOperation is raised when a result would be undefined or impossible.
InvalidOperation
// Clamped is raised when the exponent of a result has been altered or
// constrained in order to fit the constraints of the Decimal representation.
Clamped
)
// Any returns true if any flag is true.
func (r Condition) Any() bool { return r != 0 }
// SystemOverflow returns true if the SystemOverflow flag is set.
func (r Condition) SystemOverflow() bool { return r&SystemOverflow != 0 }
// SystemUnderflow returns true if the SystemUnderflow flag is set.
func (r Condition) SystemUnderflow() bool { return r&SystemUnderflow != 0 }
// Overflow returns true if the Overflow flag is set.
func (r Condition) Overflow() bool { return r&Overflow != 0 }
// Underflow returns true if the Underflow flag is set.
func (r Condition) Underflow() bool { return r&Underflow != 0 }
// Inexact returns true if the Inexact flag is set.
func (r Condition) Inexact() bool { return r&Inexact != 0 }
// Subnormal returns true if the Subnormal flag is set.
func (r Condition) Subnormal() bool { return r&Subnormal != 0 }
// Rounded returns true if the Rounded flag is set.
func (r Condition) Rounded() bool { return r&Rounded != 0 }
// DivisionUndefined returns true if the DivisionUndefined flag is set.
func (r Condition) DivisionUndefined() bool { return r&DivisionUndefined != 0 }
// DivisionByZero returns true if the DivisionByZero flag is set.
func (r Condition) DivisionByZero() bool { return r&DivisionByZero != 0 }
// DivisionImpossible returns true if the DivisionImpossible flag is set.
func (r Condition) DivisionImpossible() bool { return r&DivisionImpossible != 0 }
// InvalidOperation returns true if the InvalidOperation flag is set.
func (r Condition) InvalidOperation() bool { return r&InvalidOperation != 0 }
// Clamped returns true if the Clamped flag is set.
func (r Condition) Clamped() bool { return r&Clamped != 0 }
// GoError converts r to an error based on the given traps and returns
// r. Traps are the conditions which will trigger an error result if the
// corresponding Flag condition occurred.
func (r Condition) GoError(traps Condition) (Condition, error) {
const (
systemErrors = SystemOverflow | SystemUnderflow
)
var err error
if r&systemErrors != 0 {
err = errors.New(errExponentOutOfRangeStr)
} else if t := r & traps; t != 0 {
err = errors.New(t.String())
}
return r, err
}
func (r Condition) String() string {
var names []string
for i := Condition(1); r != 0; i <<= 1 {
if r&i == 0 {
continue
}
r ^= i
var s string
switch i {
case SystemOverflow, SystemUnderflow:
continue
case Overflow:
s = "overflow"
case Underflow:
s = "underflow"
case Inexact:
s = "inexact"
case Subnormal:
s = "subnormal"
case Rounded:
s = "rounded"
case DivisionUndefined:
s = "division undefined"
case DivisionByZero:
s = "division by zero"
case DivisionImpossible:
s = "division impossible"
case InvalidOperation:
s = "invalid operation"
case Clamped:
s = "clamped"
default:
panic(fmt.Errorf("unknown condition %d", i))
}
names = append(names, s)
}
return strings.Join(names, ", ")
}
// negateOverflowFlags converts Overflow and SystemOverflow flags into their
// equivalent Underflows.
func (r Condition) negateOverflowFlags() Condition {
if r.Overflow() {
// Underflow always also means Subnormal. See GDA definition.
r |= Underflow | Subnormal
r &= ^Overflow
}
if r.SystemOverflow() {
r |= SystemUnderflow
r &= ^SystemOverflow
}
return r
}