Class: Integer
- Inherits:
-
Object
- Object
- Integer
- Defined in:
- lib/long-decimal.rb
Overview
add one method to Integer
Instance Method Summary collapse
-
#round_to_allowed_remainders(remainders, modulus, rounding_mode = LongDecimalRoundingMode::ROUND_UNNECESSARY, zero_rounding_mode = LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY) ⇒ Object
create copy of self round in such a way that the result is congruent modulo modulus to one of the members of remainders.
-
#sgn ⇒ Object
(also: #signum, #sign)
get the sign of self -1 if self < 0 0 if self is 0 (with any number of 0s after the decimal point) +1 if self > 0.
Instance Method Details
#round_to_allowed_remainders(remainders, modulus, rounding_mode = LongDecimalRoundingMode::ROUND_UNNECESSARY, zero_rounding_mode = LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY) ⇒ Object
create copy of self round in such a way that the result is congruent modulo modulus to one of the members of remainders
param1: remainders array of allowed remainders param2: modulus modulus of the remainders param3: rounding_mode rounding mode to be applied when information is
lost. defaults to ROUND_UNNECESSARY, which
means that an exception is thrown if rounding
would actually loose any information.
param4: zero_rounding_mode if self is zero, but zero is not among
the available remainders, it has to be
rounded to positive or negative value.
If the rounding_mode does not allow to
determine which of the two values to
use, zero_rounding_mode has to be used
to decide.
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 349 |
# File 'lib/long-decimal.rb', line 224 def round_to_allowed_remainders(remainders, modulus, rounding_mode = LongDecimalRoundingMode::ROUND_UNNECESSARY, zero_rounding_mode = LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY) raise TypeError, "remainders must be Array" unless remainders.kind_of? Array raise TypeError, "remainders must be non-empty Array" unless remainders.length > 0 raise TypeError, "modulus #{modulus.inspect} must be integer" unless modulus.kind_of? Integer raise TypeError, "modulus #{modulus.inspect} must be >= 2" unless modulus >= 2 raise TypeError, "rounding_mode #{rounding_mode.inspect} must be legal rounding rounding_mode" unless rounding_mode.kind_of? LongDecimalRoundingMode::RoundingModeClass raise TypeError, "ROUND_HALF_EVEN is not applicable here" if rounding_mode == LongDecimalRoundingMode::ROUND_HALF_EVEN raise TypeError, "zero_rounding_mode #{zero_rounding_mode.inspect} must be legal zero_rounding zero_rounding_mode" unless zero_rounding_mode.kind_of? LongDecimalRoundingMode::ZeroRoundingModeClass r_self = self % modulus r_self_00 = r_self remainders = remainders.collect do |r| raise TypeError, "remainders must be numbers" unless r.kind_of? Integer r % modulus end remainders.sort!.uniq! r_first = remainders[0] r_last = remainders[-1] r_first_again = r_first + modulus remainders.push r_first_again if (r_self < r_first) then r_self += modulus end r_lower = -1 r_upper = -1 remainders.each_index do |i| r = remainders[i] if (r == r_self) then return self elsif (r < r_self) then r_lower = r elsif (r > r_self) then r_upper = r break end end lower = self - (r_self - r_lower) upper = self + (r_upper - r_self) unless (lower < self && self < upper) raise ArgumentError, "self=#{self} not in (#{lower}, #{upper})" end if (rounding_mode == LongDecimalRoundingMode::ROUND_UNNECESSARY) then raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, self=#{self.to_s} is in open interval (#{lower}, #{upper})" end # if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then # return lower # elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then # return upper # end sign_self = self.sign if (sign_self == 0) then if (rounding_mode == LongDecimalRoundingMode::ROUND_UP || rounding_mode == LongDecimalRoundingMode::ROUND_DOWN \ || lower == -upper && (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_UP || rounding_mode == LongDecimalRoundingMode::ROUND_HALF_DOWN)) if (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY) then raise ArgumentError, "self=#{self.to_s} is 0 in open interval (#{lower}, #{upper}) and cannot be resolved with ZERO_ROUND_UNNECESSARY" elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_PLUS \ || zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_MINUS) then diff = lower.abs <=> upper.abs if (diff < 0) then return lower elsif (diff > 0) then return upper elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_PLUS) then return upper elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_MINUS) then return lower else raise ArgumentError, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}" end elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_PLUS) then return upper elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_MINUS) then return lower else raise ArgumentError, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}" end end end # now we can assume that sign_self (and self) is != 0, which allows to decide on the rounding_mode if (rounding_mode == LongDecimalRoundingMode::ROUND_UP) # ROUND_UP goes to the closest possible value away from zero rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_FLOOR : LongDecimalRoundingMode::ROUND_CEILING elsif (rounding_mode == LongDecimalRoundingMode::ROUND_DOWN) # ROUND_DOWN goes to the closest possible value towards zero or beyond zero rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_CEILING : LongDecimalRoundingMode::ROUND_FLOOR elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_UP) # ROUND_HALF_UP goes to the closest possible value preferring away from zero rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_HALF_FLOOR : LongDecimalRoundingMode::ROUND_HALF_CEILING elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_DOWN) # ROUND_HALF_DOWN goes to the closest possible value preferring towards zero or beyond zero rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_HALF_CEILING : LongDecimalRoundingMode::ROUND_HALF_FLOOR end if (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_FLOOR \ || rounding_mode == LongDecimalRoundingMode::ROUND_HALF_CEILING) then d_lower = self - lower d_upper = upper - self if (d_lower < d_upper) then return lower elsif (d_upper < d_lower) then return upper elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_FLOOR) then rounding_mode = LongDecimalRoundingMode::ROUND_FLOOR elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_CEILING) then rounding_mode = LongDecimalRoundingMode::ROUND_CEILING else raise ArgumentError, "this case can never happen: rounding_mode=#{rounding_mode}" end end if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then return lower elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then return upper else raise ArgumentError, "this case can never happen: rounding_mode=#{rounding_mode}" end end |
#sgn ⇒ Object Also known as: signum, sign
get the sign of self -1 if self < 0
0 if self is 0 (with any number of 0s after the decimal point)
+1 if self > 0
199 200 201 |
# File 'lib/long-decimal.rb', line 199 def sgn self <=> 0 end |