View Javadoc
1   //******************************************************************************
2   //
3   // File:    SharedFloat.java
4   // Package: edu.rit.pj.reduction
5   // Unit:    Class edu.rit.pj.reduction.SharedFloat
6   //
7   // This Java source file is copyright (C) 2007 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.pj.reduction;
41  
42  import java.io.Serial;
43  import java.util.concurrent.atomic.AtomicInteger;
44  
45  /**
46   * Class SharedFloat provides a reduction variable for a value of type
47   * <code>float</code>.
48   * <P>
49   * Class SharedFloat is multiple thread safe. The methods use lock-free atomic
50   * compare-and-set.
51   * <P>
52   * <I>Note:</I> Class SharedFloat is implemented using class
53   * java.util.concurrent.atomic.AtomicInteger. The float value is stored as an
54   * <code>int</code> whose bit pattern is the same as the float value.
55   *
56   * @author Alan Kaminsky
57   * @version 07-Jun-2007
58   */
59  public class SharedFloat
60          extends Number {
61  
62      @Serial
63      private static final long serialVersionUID = 1L;
64  
65  // Hidden data members.
66      private AtomicInteger myValue;
67  
68  // Exported constructors.
69      /**
70       * Construct a new float reduction variable with the initial value 0.
71       */
72      public SharedFloat() {
73          myValue = new AtomicInteger(Float.floatToIntBits(0.0f));
74      }
75  
76      /**
77       * Construct a new float reduction variable with the given initial value.
78       *
79       * @param initialValue Initial value.
80       */
81      public SharedFloat(float initialValue) {
82          myValue = new AtomicInteger(Float.floatToIntBits(initialValue));
83      }
84  
85  // Exported operations.
86      /**
87       * Returns this reduction variable's current value.
88       *
89       * @return Current value.
90       */
91      public float get() {
92          return Float.intBitsToFloat(myValue.get());
93      }
94  
95      /**
96       * Set this reduction variable to the given value.
97       *
98       * @param value New value.
99       */
100     public void set(float value) {
101         myValue.set(Float.floatToIntBits(value));
102     }
103 
104     /**
105      * Set this reduction variable to the given value and return the previous
106      * value.
107      *
108      * @param value New value.
109      * @return Previous value.
110      */
111     public float getAndSet(float value) {
112         return Float.intBitsToFloat(myValue.getAndSet(Float.floatToIntBits(value)));
113     }
114 
115     /**
116      * Atomically set this reduction variable to the given updated value if the
117      * current value equals the expected value.
118      *
119      * @param expect Expected value.
120      * @param update Updated value.
121      * @return True if the update happened, false otherwise.
122      */
123     public boolean compareAndSet(float expect,
124             float update) {
125         return myValue.compareAndSet(Float.floatToIntBits(expect), Float.floatToIntBits(update));
126     }
127 
128     /**
129      * Atomically set this reduction variable to the given updated value if the
130      * current value equals the expected value. May fail spuriously.
131      *
132      * @param expect Expected value.
133      * @param update Updated value.
134      * @return True if the update happened, false otherwise.
135      */
136     @SuppressWarnings("deprecation")
137     public boolean weakCompareAndSet(float expect,
138             float update) {
139         return myValue.weakCompareAndSet(Float.floatToIntBits(expect), Float.floatToIntBits(update));
140     }
141 
142     /**
143      * Add one to this reduction variable and return the previous value.
144      *
145      * @return Previous value.
146      */
147     public float getAndIncrement() {
148         for (;;) {
149             int oldvalueInt = myValue.get();
150             float oldvalue = Float.intBitsToFloat(oldvalueInt);
151             float newvalue = oldvalue + 1.0f;
152             int newvalueInt = Float.floatToIntBits(newvalue);
153             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
154                 return oldvalue;
155             }
156         }
157     }
158 
159     /**
160      * Subtract one from this reduction variable and return the previous value.
161      *
162      * @return Previous value.
163      */
164     public float getAndDecrement() {
165         for (;;) {
166             int oldvalueInt = myValue.get();
167             float oldvalue = Float.intBitsToFloat(oldvalueInt);
168             float newvalue = oldvalue - 1.0f;
169             int newvalueInt = Float.floatToIntBits(newvalue);
170             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
171                 return oldvalue;
172             }
173         }
174     }
175 
176     /**
177      * Add the given value to this reduction variable and return the previous
178      * value.
179      *
180      * @param value Value to add.
181      * @return Previous value.
182      */
183     public float getAndAdd(float value) {
184         for (;;) {
185             int oldvalueInt = myValue.get();
186             float oldvalue = Float.intBitsToFloat(oldvalueInt);
187             float newvalue = oldvalue + value;
188             int newvalueInt = Float.floatToIntBits(newvalue);
189             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
190                 return oldvalue;
191             }
192         }
193     }
194 
195     /**
196      * Add one to this reduction variable and return the new value.
197      *
198      * @return New value.
199      */
200     public float incrementAndGet() {
201         for (;;) {
202             int oldvalueInt = myValue.get();
203             float oldvalue = Float.intBitsToFloat(oldvalueInt);
204             float newvalue = oldvalue + 1.0f;
205             int newvalueInt = Float.floatToIntBits(newvalue);
206             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
207                 return newvalue;
208             }
209         }
210     }
211 
212     /**
213      * Subtract one from this reduction variable and return the new value.
214      *
215      * @return New value.
216      */
217     public float decrementAndGet() {
218         for (;;) {
219             int oldvalueInt = myValue.get();
220             float oldvalue = Float.intBitsToFloat(oldvalueInt);
221             float newvalue = oldvalue - 1.0f;
222             int newvalueInt = Float.floatToIntBits(newvalue);
223             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
224                 return newvalue;
225             }
226         }
227     }
228 
229     /**
230      * Add the given value to this reduction variable and return the new value.
231      *
232      * @param value Value to add.
233      * @return New value.
234      */
235     public float addAndGet(float value) {
236         for (;;) {
237             int oldvalueInt = myValue.get();
238             float oldvalue = Float.intBitsToFloat(oldvalueInt);
239             float newvalue = oldvalue + value;
240             int newvalueInt = Float.floatToIntBits(newvalue);
241             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
242                 return newvalue;
243             }
244         }
245     }
246 
247     /**
248      * Combine this reduction variable with the given value using the given
249      * operation. The result is stored back into this reduction variable and is
250      * returned.
251      *
252      * @param value Value.
253      * @param op Binary operation.
254      * @return (This variable) <I>op</I> (<code>value</code>).
255      */
256     public float reduce(float value,
257             FloatOp op) {
258         for (;;) {
259             int oldvalueInt = myValue.get();
260             float oldvalue = Float.intBitsToFloat(oldvalueInt);
261             float newvalue = op.op(oldvalue, value);
262             int newvalueInt = Float.floatToIntBits(newvalue);
263             if (myValue.compareAndSet(oldvalueInt, newvalueInt)) {
264                 return newvalue;
265             }
266         }
267     }
268 
269     /**
270      * Returns a string version of this reduction variable.
271      *
272      * @return String version.
273      */
274     public String toString() {
275         return Float.toString(get());
276     }
277 
278     /**
279      * Returns this reduction variable's current value converted to type
280      * <code>int</code>.
281      *
282      * @return Current value.
283      */
284     public int intValue() {
285         return (int) get();
286     }
287 
288     /**
289      * Returns this reduction variable's current value converted to type
290      * <code>long</code>.
291      *
292      * @return Current value.
293      */
294     public long longValue() {
295         return (long) get();
296     }
297 
298     /**
299      * Returns this reduction variable's current value converted to type
300      * <code>float</code>.
301      *
302      * @return Current value.
303      */
304     public float floatValue() {
305         return get();
306     }
307 
308     /**
309      * Returns this reduction variable's current value converted to type
310      * <code>double</code>.
311      *
312      * @return Current value.
313      */
314     public double doubleValue() {
315         return get();
316     }
317 
318 }