1 // This code has been mechanically translated from the original FORTRAN 2 // code at http://netlib.org/minpack. 3 4 /** Authors: Lars Tandle Kyllingstad 5 Copyright: Copyright (c) 2009, Lars T. Kyllingstad. All rights reserved. 6 License: Boost Licence 1.0 7 */ 8 module scid.ports.minpack.enorm; 9 10 11 import std.math; 12 13 14 15 /** Given an n-vector x, this function calculates the 16 Euclidean norm of x. 17 18 The Euclidean norm is computed by accumulating the sum of 19 squares in three different sums. The sums of squares for the 20 small and large components are scaled so that no overflows 21 occur. Non-destructive underflows are permitted. Underflows 22 and overflows do not occur in the computation of the unscaled 23 sum of squarees for the intermediate components. 24 The definitions of small, intermediate and large components 25 depend on two constants, rdwarf and rgiant. The main 26 restrictions on these constants are that rdwarf^2 not 27 underflow and rgiant^2 not overflow. The constants 28 given here are suitable for every known computer. 29 30 Parameters: 31 x = an input array. 32 */ 33 Real enorm(Real)(size_t n, Real* x) 34 { 35 enum : Real 36 { 37 one = 1.0, 38 zero = 0.0, 39 rdwarf = 3.834e-20, 40 rgiant = 1.304e19 41 } 42 43 Real s1 = zero; 44 Real s2 = zero; 45 Real s3 = zero; 46 Real x1max = zero; 47 Real x3max = zero; 48 immutable Real floatn = n; 49 immutable Real agiant = rgiant/floatn; 50 51 Real xabs; 52 for (size_t i=0; i<n; i++) 53 { 54 xabs = abs(x[i]); 55 if (xabs <= rdwarf || xabs >= agiant) 56 { 57 if (xabs > rdwarf) 58 { 59 // Sum for large components. 60 if (xabs > x1max) 61 { 62 s1 = one + s1*((x1max/xabs)^^2); 63 x1max = xabs; 64 } 65 else 66 { 67 s1 += (xabs/x1max)^^2; 68 } 69 } 70 else 71 { 72 // Sum for small components. 73 if (xabs > x3max) 74 { 75 s3 = one + s3*((x3max/xabs)^^2); 76 x3max = xabs; 77 } 78 else 79 { 80 if (xabs != zero) s3 += (xabs/x3max)^^2; 81 } 82 } 83 } 84 else 85 { 86 // Sum for intermediate components. 87 s2 += xabs*xabs; 88 } 89 } 90 91 92 // Calculation of norm. 93 Real result; 94 if (s1 != zero) 95 { 96 result = x1max*sqrt(s1+(s2/x1max)/x1max); 97 } 98 else 99 { 100 if (s2 != zero) 101 { 102 if (s2 >= x3max) 103 result = sqrt(s2*(one+(x3max/s2)*(x3max*s3))); 104 else 105 result = sqrt(x3max*((s2/x3max)+(x3max*s3))); 106 } 107 else 108 { 109 result = x3max*sqrt(s3); 110 } 111 } 112 113 return result; 114 } 115 116 117 unittest 118 { 119 double[] v = [ 1.0, 2.0, 3.0 ]; 120 double norm = enorm(3, v.ptr); 121 assert (abs(norm-sqrt(14.0)) < 1e-10); 122 } 123