View Javadoc
1   //******************************************************************************
2   //
3   // File:    SharedDouble.java
4   // Package: edu.rit.pj.reduction
5   // Unit:    Class edu.rit.pj.reduction.SharedDouble
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.AtomicLong;
44  
45  /**
46   * Class SharedDouble provides a reduction variable for a value of type
47   * <code>double</code>.
48   * <P>
49   * Class SharedDouble is multiple thread safe. The methods use lock-free atomic
50   * compare-and-set.
51   * <P>
52   * <I>Note:</I> Class SharedDouble is implemented using class
53   * java.util.concurrent.atomic.AtomicLong. The double value is stored as a
54   * <code>long</code> whose bit pattern is the same as the double value.
55   *
56   * @author Alan Kaminsky
57   * @version 07-Jun-2007
58   */
59  public class SharedDouble
60          extends Number {
61  
62      @Serial
63      private static final long serialVersionUID = 1L;
64  
65  // Hidden data members.
66      private AtomicLong myValue;
67  
68  // Exported constructors.
69      /**
70       * Construct a new double reduction variable with the initial value 0.
71       */
72      public SharedDouble() {
73          myValue = new AtomicLong(Double.doubleToLongBits(0.0));
74      }
75  
76      /**
77       * Construct a new double reduction variable with the given initial value.
78       *
79       * @param initialValue Initial value.
80       */
81      public SharedDouble(double initialValue) {
82          myValue = new AtomicLong(Double.doubleToLongBits(initialValue));
83      }
84  
85  // Exported operations.
86      /**
87       * Returns this reduction variable's current value.
88       *
89       * @return Current value.
90       */
91      public double get() {
92          return Double.longBitsToDouble(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(double value) {
101         myValue.set(Double.doubleToLongBits(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 double getAndSet(double value) {
112         return Double.longBitsToDouble(myValue.getAndSet(Double.doubleToLongBits(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(double expect,
124             double update) {
125         return myValue.compareAndSet(Double.doubleToLongBits(expect), Double.doubleToLongBits(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(double expect,
138             double update) {
139         return myValue.weakCompareAndSet(Double.doubleToLongBits(expect), Double.doubleToLongBits(update));
140     }
141 
142     /**
143      * Add one to this reduction variable and return the previous value.
144      *
145      * @return Previous value.
146      */
147     public double getAndIncrement() {
148         for (;;) {
149             long oldvalueLong = myValue.get();
150             double oldvalue = Double.longBitsToDouble(oldvalueLong);
151             double newvalue = oldvalue + 1.0;
152             long newvalueLong = Double.doubleToLongBits(newvalue);
153             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double getAndDecrement() {
165         for (;;) {
166             long oldvalueLong = myValue.get();
167             double oldvalue = Double.longBitsToDouble(oldvalueLong);
168             double newvalue = oldvalue - 1.0;
169             long newvalueLong = Double.doubleToLongBits(newvalue);
170             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double getAndAdd(double value) {
184         for (;;) {
185             long oldvalueLong = myValue.get();
186             double oldvalue = Double.longBitsToDouble(oldvalueLong);
187             double newvalue = oldvalue + value;
188             long newvalueLong = Double.doubleToLongBits(newvalue);
189             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double incrementAndGet() {
201         for (;;) {
202             long oldvalueLong = myValue.get();
203             double oldvalue = Double.longBitsToDouble(oldvalueLong);
204             double newvalue = oldvalue + 1.0;
205             long newvalueLong = Double.doubleToLongBits(newvalue);
206             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double decrementAndGet() {
218         for (;;) {
219             long oldvalueLong = myValue.get();
220             double oldvalue = Double.longBitsToDouble(oldvalueLong);
221             double newvalue = oldvalue - 1.0;
222             long newvalueLong = Double.doubleToLongBits(newvalue);
223             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double addAndGet(double value) {
236         for (;;) {
237             long oldvalueLong = myValue.get();
238             double oldvalue = Double.longBitsToDouble(oldvalueLong);
239             double newvalue = oldvalue + value;
240             long newvalueLong = Double.doubleToLongBits(newvalue);
241             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 double reduce(double value,
257             DoubleOp op) {
258         for (;;) {
259             long oldvalueLong = myValue.get();
260             double oldvalue = Double.longBitsToDouble(oldvalueLong);
261             double newvalue = op.op(oldvalue, value);
262             long newvalueLong = Double.doubleToLongBits(newvalue);
263             if (myValue.compareAndSet(oldvalueLong, newvalueLong)) {
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 Double.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 (float) 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 }