Class: LongDecimalRoundingMode::RoundingModeClass
- Inherits:
-
Struct
- Object
- Struct
- LongDecimalRoundingMode::RoundingModeClass
- Includes:
- Comparable
- Defined in:
- lib/long-decimal.rb,
lib/long-decimal.rb
Overview
enumeration class to express the possible rounding modes that are supported by LongDecimal
Instance Method Summary collapse
-
#<=>(o) ⇒ Object
introduce some ordering for rounding modes.
-
#ainverse ⇒ Object
inverse mode in terms of addition.
- #hash ⇒ Object
-
#minverse ⇒ Object
inverse mode in terms of multiplication.
-
#pick_value(unrounded, sign, lower, upper, even) ⇒ Object
internal use no special checks included we assume: lower <= unrounded <= upper we assume: sign = sgn(unrounded).
- #to_long_s ⇒ Object
- #to_s ⇒ Object
Instance Method Details
#<=>(o) ⇒ Object
introduce some ordering for rounding modes
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/long-decimal.rb', line 146 def <=>(o) if o.respond_to?:num self.num <=> o.num elsif o.kind_of? Numeric self.num <=> o else puts("stack=#{caller.join("\n")}") raise TypeError, "o=#{o.inspect} must be numeric or RoundingMode"; end end |
#ainverse ⇒ Object
inverse mode in terms of addition
167 168 169 |
# File 'lib/long-decimal.rb', line 167 def ainverse LongDecimalRoundingMode::ADD_INVERSE_MODE[self] end |
#hash ⇒ Object
350 351 352 |
# File 'lib/long-decimal.rb', line 350 def hash num end |
#minverse ⇒ Object
inverse mode in terms of multiplication
160 161 162 |
# File 'lib/long-decimal.rb', line 160 def minverse LongDecimalRoundingMode::MUL_INVERSE_MODE[self] end |
#pick_value(unrounded, sign, lower, upper, even) ⇒ Object
internal use no special checks included we assume: lower <= unrounded <= upper we assume: sign = sgn(unrounded)
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/long-decimal.rb', line 175 def pick_value(unrounded, sign, lower, upper, even) if (sign == 0 || major == MAJOR_UNNECESSARY) if (lower == unrounded) return lower elsif (upper == unrounded) return upper end end if (major == MAJOR_UP && sign > 0) return upper elsif (major == MAJOR_UP && sign < 0) return lower elsif (major == MAJOR_DOWN && sign > 0) return lower elsif (major == MAJOR_DOWN && sign < 0) return upper elsif (major == MAJOR_CEILING) return upper elsif (major == MAJOR_FLOOR) return lower elsif (major == MAJOR_UNNECESSARY) raise ArgumentError, "rounding #{name} of unrounded=#{unrounded} (sign=#{sign}) is not applicable for lower=#{lower} and upper=#{upper}" end on_boundary = false if (major == MAJOR_HALF) d = unrounded - lower <=> upper - unrounded if (d < 0) # unrounded is below half return lower elsif (d > 0) # unrounded is below half return upper else on_boundary = true end elsif (major == MAJOR_GEOMETRIC) prod = lower * upper if (prod < 0) raise ArgumentError, "geometric rounding #{name} of unrounded=#{unrounded} (sign=#{sign}) is not applicable for lower=#{lower} and upper=#{upper} with different signs" elsif (prod == 0) # lower or upper is 0 # we only round 0 to 0 if (sign == 0) raise ArgumentError, "geometric rounding #{name} of unrounded=#{unrounded} (sign=#{sign}) is not applicable for lower=#{lower} and upper=#{upper} with 0 cannot be decided" elsif (sign < 0) return lower else return upper end end # now prod > 0 square = unrounded * unrounded d = square <=> prod if (d < 0) # |unrounded| < sqrt(lower*upper) if (sign < 0) # lower < unrounded < upper < 0 return upper else # (sign > 0) return lower end elsif (d > 0) # |unrounded| > sqrt(lower*upper) if (sign < 0) # lower < unrounded < upper < 0 return lower else # (sign > 0) return upper end else # (d == 0) on_boundary = true end elsif (major == MAJOR_HARMONIC) prod = lower * upper if (prod < 0) raise ArgumentError, "harmonic rounding #{name} of unrounded=#{unrounded} is not applicable for lower=#{lower} and upper=#{upper} with different signs" elsif (prod == 0) # lower or upper is 0 # we only round 0 to 0 if (sign == 0) raise ArgumentError, "harmonic rounding #{name} of unrounded=#{unrounded} is not applicable for lower=#{lower} and upper=#{upper} with 0 cannot be decided" elsif (sign < 0) return lower else return upper end end # now prod > 0 # so either lower < unrounded < upper < 0 # or 0 < lower < unrounded < upper sum = lower + upper lhs = unrounded * sum rhs = 2*prod d = lhs <=> rhs if (sign < 0) # lower + upper < 0 d = -d end if (d < 0) # unrounded < 2*upper*lower/(upper+lower) return lower elsif (d > 0) # unrounded > 2*upper*lower/(upper+lower) return upper else # (d == 0) on_boundary = true end elsif (major == MAJOR_QUADRATIC) square = unrounded * unrounded lhs = 2 * square rhs = lower * lower + upper * upper d = lhs <=> rhs if (sign < 0) # lower <= unrounded <= upper <= 0 # lower^2 >= unrounded >= upper^2 >= 0 d = -d end if (d < 0) # unrounded < sqrt(...) return lower elsif (d > 0) # unrounded > sqrt(...) return upper else # (d == 0) on_boundary = true end elsif (major == MAJOR_CUBIC) cube = unrounded ** 3 lhs = 2 * cube rhs = lower ** 3 + upper ** 3 d = lhs <=> rhs if (d < 0) # unrounded < x_cubic(lower, upper) return lower elsif (d > 0) # unrounded > x_cubic(lower, upper) return upper else # (d == 0) on_boundary = true end else raise ArgumentError, "unsupported rounding mode (#{name}: major=#{major})" end if (! on_boundary) raise ArgumentError, "rounding #{name} of unrounded=#{unrounded} failed for lower=#{lower} and upper=#{upper}: not on boundary" end if (minor == MINOR_UP) return ROUND_UP.pick_value(unrounded, sign, lower, upper, even) elsif (minor == MINOR_DOWN) return ROUND_DOWN.pick_value(unrounded, sign, lower, upper, even) elsif (minor == MINOR_CEILING) return ROUND_CEILING.pick_value(unrounded, sign, lower, upper, even) elsif (minor == MINOR_FLOOR) return ROUND_FLOOR.pick_value(unrounded, sign, lower, upper, even) elsif (minor == MINOR_UNUSED) raise ArgumentError, "rounding #{name} of unrounded=#{unrounded} failed for lower=#{lower} and upper=#{upper}: on boundary but no applicable minor mode" elsif (minor == MINOR_EVEN) return even elsif (minor == MINOR_ODD) if (lower == even) return upper else return lower end else raise ArgumentError, "rounding #{name} of unrounded=#{unrounded} failed for lower=#{lower} and upper=#{upper}: on boundary but no applicable minor mode" end end |
#to_long_s ⇒ Object
354 355 356 |
# File 'lib/long-decimal.rb', line 354 def to_long_s "RM(#{name} major=#{major.name} minor=#{minor.name} num=#{num})" end |
#to_s ⇒ Object
358 359 360 |
# File 'lib/long-decimal.rb', line 358 def to_s "#{name}" end |