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
167
168
169
170
171
172
173
174
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
|
#ifndef RBIMPL_INTERN_NUMERIC_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_NUMERIC_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Public APIs related to ::rb_cNumeric.
*/
#include "ruby/internal/attr/cold.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
/**
* @private
*
* @deprecated This macro once was a thing in the old days, but makes no sense
* any longer today. Exists here for backwards compatibility
* only. You can safely forget about it.
*/
#define RB_NUM_COERCE_FUNCS_NEED_OPID 1
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* numeric.c */
RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_COLD()
/**
* Just always raises an exception.
*
* @exception rb_eZeroDivError Division by zero error.
*/
void rb_num_zerodiv(void);
/**
* @name Coercion operators.
*
* What is a coercion? Well Ruby is basically an OOPL but it also has
* arithmetic operators. They are implemented in OO manners. For instance
* `a+b` is a binary operation `+`, whose receiver is `a`, and whose (sole)
* argument is `b`.
*
* The problem is, you often want `a+b == b+a` to hold. That is easy if both
* `a` and `b` belongs to the same class... Ensuring `1 + 2 == 2 + 1` is kind
* of intuitive. But if you want `1.0 + 2 == 2 + 1.0`, things start getting
* complicated. `1.0+2` is `Float#+`, while `2+1.0` is `Integer#+`. In order
* to achieve the equality Float's and Integer's methods must agree with their
* behaviours.
*
* Now. Floats versus Integers situation is still controllable because they
* are both built-in. But in Ruby you can define your own numeric classes.
* BigDecimal, which is a rubygems gem distributed along with the interpreter,
* is one of such examples. Rational was another such example before. In
* short you cannot create list of all possible combination of the classes that
* could be the operand of `+` operator. Then how do we achieve the
* commutativity?
*
* Here comes the concept of coercion. If a definition of an operator
* encounters an object which is unknown to the author, just assumes that the
* unknown object knows how to handle the situation. So for instance when
* `1+x` has unknown `x`, it lets the `x` handle this.
*
* ```ruby
* class Foo
* def +(x)
* if we_know_what_is_x? then
* ... # handle here
* else
* y, z = x.coerce self
* return y + z
* end
* end
* end
* ```
*
* The `x.coerce` method returns a 2-element array which are "casted" versions
* of `x` and `self`.
*
* @{
*/
/**
* Coerced binary operation. This function first coerces the two objects, then
* applies the operation.
*
* @param[in] lhs LHS operand.
* @param[in] rhs RHS operand.
* @param[in] op Operator method name.
* @exception rb_eTypeError Coercion failed for some reason.
* @return `lhs op rhs`, in a coerced way.
*/
VALUE rb_num_coerce_bin(VALUE lhs, VALUE rhs, ID op);
/**
* Identical to rb_num_coerce_bin(), except for return values. This function
* best suits for comparison operators e.g. `<=>`.
*
* @param[in] lhs LHS operand.
* @param[in] rhs RHS operand.
* @param[in] op Operator method name.
* @retval RUBY_Qnil Coercion failed for some reason.
* @retval otherwise `lhs op rhs`, in a coerced way.
*/
VALUE rb_num_coerce_cmp(VALUE lhs, VALUE rhs, ID op);
/**
* Identical to rb_num_coerce_cmp(), except for return values. This function
* best suits for relationship operators e.g. `<=`.
*
* @param[in] lhs LHS operand.
* @param[in] rhs RHS operand.
* @param[in] op Operator method name.
* @exception rb_eArgError Coercion failed for some reason.
* @return `lhs op rhs`, in a coerced way.
*/
VALUE rb_num_coerce_relop(VALUE lhs, VALUE rhs, ID op);
/**
* This one is optimised for bitwise operations, but the API is identical to
* rb_num_coerce_bin().
*
* @param[in] lhs LHS operand.
* @param[in] rhs RHS operand.
* @param[in] op Operator method name.
* @exception rb_eArgError Coercion failed for some reason.
* @return `lhs op rhs`, in a coerced way.
*/
VALUE rb_num_coerce_bit(VALUE lhs, VALUE rhs, ID op);
/** @} */
/**
* Converts a numeric value into a Fixnum. This is not a preserving
* conversion; for instance 1.5 would be converted into 1.
*
* @param[in] val A numeric object.
* @exception rb_eTypeError No conversion from `val` to Integer.
* @exception rb_eRangeError `val` out of range.
* @return A fixnum converted from `val`.
*
* @internal
*
* This seems used from nowhere?
*/
VALUE rb_num2fix(VALUE val);
/**
* Generates a place-value representation of the given Fixnum, with given
* radix.
*
* @param[in] val A fixnum to stringify.
* @param[in] base `2` to `36` inclusive for each radix.
* @exception rb_eArgError `base` is out of range.
* @return An instance of ::rb_cString representing `val`.
* @pre `val` must be a Fixnum (no checks performed).
*/
VALUE rb_fix2str(VALUE val, int base);
RBIMPL_ATTR_CONST()
/**
* Compares two `double`s. Handy when implementing a spaceship operator.
*
* @param[in] lhs A value.
* @param[in] rhs Another value.
* @retval RB_INT2FIX(-1) `lhs` is "bigger than" `rhs`.
* @retval RB_INT2FIX(1) `rhs` is "bigger than" `lhs`.
* @retval RB_INT2FIX(0) They are equal.
* @retval RUBY_Qnil Not comparable, e.g. NaN.
*/
VALUE rb_dbl_cmp(double lhs, double rhs);
/**
* Raises the passed `x` to the power of `y`.
*
* @note The return value can be really big.
* @note Also the return value can be really small, in case `x` is a
* negative number.
* @param[in] x A number.
* @param[in] y Another number.
* @retval Inf Cannot express the result.
* @retval 1 Either `y` is 0 or `x` is 1.
* @retval otherwise An instance of ::rb_cInteger whose value is `x ** y`.
*
* @internal
*
* This function returns Infinity when `y` is big enough not to fit into a
* Fixnum. Warning is issued then.
*/
RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_NUMERIC_H */
|