double 关键字

概述

double 是Java中的基本数据类型,表示64位双精度IEEE 754浮点数,取值范围约为±1.8E308(15-17位有效数字),是浮点运算的默认类型。

语法格式

double variableName;              // 声明double变量
double variableName = 3.14159;    // 浮点字面量(默认为double)
double variableName = 2.5d;       // 显式添加d后缀

基本特性

public class DoubleBasicsExample {
    public static void main(String[] args) {
        // 基本声明和初始化
        double d1 = 3.141592653589793;
        double d2 = -2.718281828;
        double d3 = 0.0;
        double d4 = 1.0d;           // 显式double后缀

        System.out.println("π ≈ " + d1);
        System.out.println("e ≈ " + d2);
        System.out.println("d3 = " + d3);
        System.out.println("d4 = " + d4);

        // 常量值
        System.out.println("double最小正值: " + Double.MIN_VALUE);
        System.out.println("double最大值: " + Double.MAX_VALUE);
        System.out.println("double最小正常值: " + Double.MIN_NORMAL);
        System.out.println("double精度位数: " + Double.SIZE);

        // 特殊值
        double positiveInfinity = Double.POSITIVE_INFINITY;
        double negativeInfinity = Double.NEGATIVE_INFINITY;
        double notANumber = Double.NaN;

        System.out.println("正无穷: " + positiveInfinity);
        System.out.println("负无穷: " + negativeInfinity);
        System.out.println("非数字: " + notANumber);

        // 科学计数法
        double scientific1 = 1.23e10;      // 1.23 × 10^10
        double scientific2 = 5.67e-15;     // 5.67 × 10^-15

        System.out.println("科学计数法1.23e10: " + scientific1);
        System.out.println("科学计数法5.67e-15: " + scientific2);

        // 高精度示例
        double precise = 1.23456789012345678901234567890;
        System.out.println("double高精度: " + precise);

        // 数学常量
        System.out.println("Math.PI: " + Math.PI);
        System.out.println("Math.E: " + Math.E);
    }
}

类型转换

public class DoubleConversionExample {
    public static void main(String[] args) {
        // 自动类型转换(向上转换)
        byte b = 100;
        short s = 1000;
        int i = 100000;
        long l = 1000000000L;
        float f = 3.14f;

        double fromByte = b;
        double fromShort = s;
        double fromInt = i;
        double fromLong = l;
        double fromFloat = f;

        System.out.println("byte到double: " + fromByte);
        System.out.println("short到double: " + fromShort);
        System.out.println("int到double: " + fromInt);
        System.out.println("long到double: " + fromLong);
        System.out.println("float到double: " + fromFloat);

        // 强制类型转换(可能丢失精度或溢出)
        double large = 1.7976931348623157e308;
        double decimal = 3.99999;

        // double转整数(截断小数部分)
        int intFromDouble = (int) decimal;
        long longFromDouble = (long) decimal;

        System.out.println("double转int: " + decimal + " -> " + intFromDouble);
        System.out.println("double转long: " + decimal + " -> " + longFromDouble);

        // double转float(可能丢失精度)
        double highPrecision = 1.23456789012345;
        float floatFromDouble = (float) highPrecision;

        System.out.println("高精度double: " + highPrecision);
        System.out.println("转为float: " + floatFromDouble);
        System.out.println("精度丢失: " + (highPrecision != floatFromDouble));

        // 字符串转换
        String str = "3.141592653589793";
        double doubleFromString = Double.parseDouble(str);
        System.out.println("字符串转double: " + doubleFromString);

        // double转字符串
        double value = Math.E;
        String stringFromDouble = Double.toString(value);
        System.out.println("double转字符串: " + stringFromDouble);

        // 进制转换(通过包装类)
        double hexValue = Double.parseDouble("1F", 16); // 不支持,会抛异常
        // 正确方式:先转为long再转为double
        // double hexValue = (double) Long.parseLong("1F", 16);
    }
}

精密数学运算

public class DoubleMathExample {
    public static void main(String[] args) {
        // 基本算术运算
        double a = 10.123456789;
        double b = 3.987654321;

        System.out.println("高精度运算:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("加法: " + (a + b));
        System.out.println("减法: " + (a - b));
        System.out.println("乘法: " + (a * b));
        System.out.println("除法: " + (a / b));
        System.out.println("求余: " + (a % b));

        // 高级数学函数
        double x = 2.5;
        System.out.println("\n高级数学函数:");
        System.out.println("x = " + x);
        System.out.println("√x = " + Math.sqrt(x));
        System.out.println("x² = " + Math.pow(x, 2));
        System.out.println("x³ = " + Math.pow(x, 3));
        System.out.println("e^x = " + Math.exp(x));
        System.out.println("ln(x) = " + Math.log(x));
        System.out.println("log₁₀(x) = " + Math.log10(x));

        // 三角函数
        double degrees = 60.0;
        double radians = Math.toRadians(degrees);

        System.out.println("\n三角函数 (" + degrees + "°):");
        System.out.println("sin = " + Math.sin(radians));
        System.out.println("cos = " + Math.cos(radians));
        System.out.println("tan = " + Math.tan(radians));
        System.out.println("asin = " + Math.toDegrees(Math.asin(Math.sin(radians))) + "°");
        System.out.println("acos = " + Math.toDegrees(Math.acos(Math.cos(radians))) + "°");
        System.out.println("atan = " + Math.toDegrees(Math.atan(Math.tan(radians))) + "°");

        // 双曲函数
        System.out.println("\n双曲函数:");
        System.out.println("sinh(" + x + ") = " + Math.sinh(x));
        System.out.println("cosh(" + x + ") = " + Math.cosh(x));
        System.out.println("tanh(" + x + ") = " + Math.tanh(x));

        // 舍入函数
        double value = 3.7;
        System.out.println("\n舍入函数 (" + value + "):");
        System.out.println("ceil = " + Math.ceil(value));    // 向上取整
        System.out.println("floor = " + Math.floor(value));  // 向下取整
        System.out.println("round = " + Math.round(value));  // 四舍五入
        System.out.println("rint = " + Math.rint(value));    // 就近取整

        // 随机数
        System.out.println("\n随机数:");
        for (int i = 0; i < 5; i++) {
            System.out.println("Math.random(): " + Math.random());
        }
    }
}

科学计算应用

import java.text.DecimalFormat;
import java.util.Arrays;

public class DoubleScientificExample {

    // 统计计算
    public static class Statistics {
        public static double mean(double[] data) {
            double sum = 0.0;
            for (double value : data) {
                sum += value;
            }
            return sum / data.length;
        }

        public static double variance(double[] data) {
            double mean = mean(data);
            double sumSquares = 0.0;
            for (double value : data) {
                double diff = value - mean;
                sumSquares += diff * diff;
            }
            return sumSquares / (data.length - 1);
        }

        public static double standardDeviation(double[] data) {
            return Math.sqrt(variance(data));
        }

        public static double median(double[] data) {
            double[] sorted = data.clone();
            Arrays.sort(sorted);
            int n = sorted.length;
            if (n % 2 == 0) {
                return (sorted[n/2 - 1] + sorted[n/2]) / 2.0;
            } else {
                return sorted[n/2];
            }
        }
    }

    // 数值积分(梯形法则)
    public static double trapezoidalRule(DoubleFunction function, double a, double b, int n) {
        double h = (b - a) / n;
        double sum = (function.apply(a) + function.apply(b)) / 2.0;

        for (int i = 1; i < n; i++) {
            double x = a + i * h;
            sum += function.apply(x);
        }

        return sum * h;
    }

    // 函数接口
    @FunctionalInterface
    interface DoubleFunction {
        double apply(double x);
    }

    // 牛顿法求平方根
    public static double sqrt(double n, double precision) {
        if (n < 0) return Double.NaN;
        if (n == 0) return 0;

        double x = n;
        while (true) {
            double nextX = (x + n / x) / 2.0;
            if (Math.abs(x - nextX) < precision) {
                return nextX;
            }
            x = nextX;
        }
    }

    // 复数类
    public static class Complex {
        private final double real;
        private final double imaginary;

        public Complex(double real, double imaginary) {
            this.real = real;
            this.imaginary = imaginary;
        }

        public Complex add(Complex other) {
            return new Complex(this.real + other.real, this.imaginary + other.imaginary);
        }

        public Complex multiply(Complex other) {
            double newReal = this.real * other.real - this.imaginary * other.imaginary;
            double newImaginary = this.real * other.imaginary + this.imaginary * other.real;
            return new Complex(newReal, newImaginary);
        }

        public double magnitude() {
            return Math.sqrt(real * real + imaginary * imaginary);
        }

        public double phase() {
            return Math.atan2(imaginary, real);
        }

        @Override
        public String toString() {
            if (imaginary >= 0) {
                return String.format("%.3f + %.3fi", real, imaginary);
            } else {
                return String.format("%.3f - %.3fi", real, -imaginary);
            }
        }
    }

    public static void main(String[] args) {
        System.out.println("=== 统计计算 ===");
        double[] data = {1.2, 2.3, 3.1, 4.8, 2.7, 3.9, 1.8, 2.5, 3.6, 4.2};

        System.out.println("数据: " + Arrays.toString(data));
        System.out.printf("平均值: %.3f%n", Statistics.mean(data));
        System.out.printf("方差: %.3f%n", Statistics.variance(data));
        System.out.printf("标准差: %.3f%n", Statistics.standardDeviation(data));
        System.out.printf("中位数: %.3f%n", Statistics.median(data));

        System.out.println("\n=== 数值积分 ===");
        // 计算 ∫₀¹ x² dx = 1/3
        double integral = trapezoidalRule(x -> x * x, 0.0, 1.0, 1000);
        System.out.printf("∫₀¹ x² dx ≈ %.6f (理论值: %.6f)%n", integral, 1.0/3.0);

        // 计算 ∫₀^π sin(x) dx = 2
        double sinIntegral = trapezoidalRule(Math::sin, 0.0, Math.PI, 1000);
        System.out.printf("∫₀^π sin(x) dx ≈ %.6f (理论值: 2.000000)%n", sinIntegral);

        System.out.println("\n=== 牛顿法求平方根 ===");
        double[] numbers = {4.0, 9.0, 2.0, 100.0};
        for (double num : numbers) {
            double mySqrt = sqrt(num, 1e-10);
            double mathSqrt = Math.sqrt(num);
            System.out.printf("√%.1f: 自实现=%.10f, Math.sqrt=%.10f%n", 
                            num, mySqrt, mathSqrt);
        }

        System.out.println("\n=== 复数运算 ===");
        Complex c1 = new Complex(3.0, 4.0);
        Complex c2 = new Complex(1.0, -2.0);

        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println("c1 + c2 = " + c1.add(c2));
        System.out.println("c1 * c2 = " + c1.multiply(c2));
        System.out.printf("|c1| = %.3f%n", c1.magnitude());
        System.out.printf("arg(c1) = %.3f radians%n", c1.phase());
    }
}

金融和经济计算

import java.text.NumberFormat;
import java.util.Locale;

public class DoubleFinanceExample {

    // 复利计算
    public static double compoundInterest(double principal, double rate, int periods, double time) {
        return principal * Math.pow(1 + rate / periods, periods * time);
    }

    // 现值计算
    public static double presentValue(double futureValue, double rate, double time) {
        return futureValue / Math.pow(1 + rate, time);
    }

    // 年金现值
    public static double annuityPresentValue(double payment, double rate, int periods) {
        if (rate == 0) return payment * periods;
        return payment * (1 - Math.pow(1 + rate, -periods)) / rate;
    }

    // 贷款月供计算
    public static double loanPayment(double principal, double monthlyRate, int months) {
        if (monthlyRate == 0) return principal / months;
        return principal * monthlyRate * Math.pow(1 + monthlyRate, months) / 
               (Math.pow(1 + monthlyRate, months) - 1);
    }

    // 内部收益率(IRR)近似计算
    public static double approximateIRR(double[] cashFlows, double guess) {
        double rate = guess;
        double precision = 1e-6;
        int maxIterations = 100;

        for (int i = 0; i < maxIterations; i++) {
            double npv = 0.0;
            double dnpv = 0.0;

            for (int j = 0; j < cashFlows.length; j++) {
                double factor = Math.pow(1 + rate, j);
                npv += cashFlows[j] / factor;
                dnpv -= j * cashFlows[j] / (factor * (1 + rate));
            }

            if (Math.abs(npv) < precision) {
                return rate;
            }

            rate = rate - npv / dnpv;
        }

        return Double.NaN; // 未收敛
    }

    // 波动率计算
    public static double volatility(double[] returns) {
        if (returns.length < 2) return 0.0;

        double mean = 0.0;
        for (double ret : returns) {
            mean += ret;
        }
        mean /= returns.length;

        double variance = 0.0;
        for (double ret : returns) {
            variance += Math.pow(ret - mean, 2);
        }
        variance /= returns.length - 1;

        return Math.sqrt(variance * 252); // 年化波动率(假设252个交易日)
    }

    public static void main(String[] args) {
        NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CHINA);
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMaximumFractionDigits(2);

        System.out.println("=== 复利计算 ===");
        double principal = 100000.0;  // 本金10万
        double annualRate = 0.06;     // 年利率6%
        double time = 10.0;           // 10年

        double futureValue = compoundInterest(principal, annualRate, 1, time);
        System.out.println("本金: " + currency.format(principal));
        System.out.println("年利率: " + percent.format(annualRate));
        System.out.println("时间: " + time + " 年");
        System.out.println("复利终值: " + currency.format(futureValue));

        System.out.println("\n=== 现值计算 ===");
        double pv = presentValue(futureValue, annualRate, time);
        System.out.println("未来值: " + currency.format(futureValue));
        System.out.println("现值: " + currency.format(pv));

        System.out.println("\n=== 贷款计算 ===");
        double loanAmount = 1000000.0;  // 贷款100万
        double monthlyRate = 0.05 / 12; // 月利率
        int months = 30 * 12;           // 30年

        double monthlyPayment = loanPayment(loanAmount, monthlyRate, months);
        double totalPayment = monthlyPayment * months;
        double totalInterest = totalPayment - loanAmount;

        System.out.println("贷款金额: " + currency.format(loanAmount));
        System.out.println("年利率: " + percent.format(0.05));
        System.out.println("贷款期限: " + (months/12) + " 年");
        System.out.println("月供: " + currency.format(monthlyPayment));
        System.out.println("总还款: " + currency.format(totalPayment));
        System.out.println("总利息: " + currency.format(totalInterest));

        System.out.println("\n=== 投资分析 ===");
        // 年金现值计算
        double annualPayment = 50000.0;  // 年金5万
        double discountRate = 0.08;      // 折现率8%
        int years = 20;                  // 20年

        double annuityPV = annuityPresentValue(annualPayment, discountRate, years);
        System.out.println("年金: " + currency.format(annualPayment));
        System.out.println("折现率: " + percent.format(discountRate));
        System.out.println("期限: " + years + " 年");
        System.out.println("年金现值: " + currency.format(annuityPV));

        System.out.println("\n=== IRR计算 ===");
        double[] cashFlows = {-100000, 20000, 30000, 40000, 50000, 60000}; // 投资现金流
        double irr = approximateIRR(cashFlows, 0.1);

        System.out.println("现金流: " + java.util.Arrays.toString(cashFlows));
        if (!Double.isNaN(irr)) {
            System.out.println("内部收益率(IRR): " + percent.format(irr));
        } else {
            System.out.println("IRR计算未收敛");
        }

        System.out.println("\n=== 风险计算 ===");
        double[] stockReturns = {0.12, -0.05, 0.18, 0.03, -0.08, 0.15, 0.02, -0.03, 0.09, 0.07};
        double vol = volatility(stockReturns);

        System.out.println("股票收益率: " + java.util.Arrays.toString(stockReturns));
        System.out.println("年化波动率: " + percent.format(vol));
    }
}

最佳实践

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;

public class DoubleBestPractices {

    // 1. 精确的浮点数比较
    public static boolean doubleEquals(double a, double b, double epsilon) {
        if (Double.isNaN(a) || Double.isNaN(b)) {
            return Double.isNaN(a) && Double.isNaN(b);
        }
        if (Double.isInfinite(a) || Double.isInfinite(b)) {
            return a == b;
        }
        return Math.abs(a - b) < epsilon;
    }

    public static boolean doubleEquals(double a, double b) {
        return doubleEquals(a, b, 1e-9); // 默认精度
    }

    // 2. 相对误差比较(适用于大数值)
    public static boolean doubleEqualsRelative(double a, double b, double relativeEpsilon) {
        if (a == b) return true;
        if (Double.isNaN(a) || Double.isNaN(b)) return false;
        if (Double.isInfinite(a) || Double.isInfinite(b)) return false;

        double larger = Math.max(Math.abs(a), Math.abs(b));
        return Math.abs(a - b) < relativeEpsilon * larger;
    }

    // 3. 安全的数学运算
    public static double safeDivide(double dividend, double divisor) {
        if (divisor == 0.0) {
            return dividend > 0 ? Double.POSITIVE_INFINITY : 
                  dividend < 0 ? Double.NEGATIVE_INFINITY : Double.NaN;
        }
        return dividend / divisor;
    }

    public static double safeSqrt(double value) {
        return value < 0 ? Double.NaN : Math.sqrt(value);
    }

    public static double safeLog(double value) {
        return value <= 0 ? Double.NaN : Math.log(value);
    }

    // 4. 数值稳定的计算
    public static double stableSum(double[] values) {
        // Kahan求和算法,减少浮点累积误差
        double sum = 0.0;
        double compensation = 0.0;

        for (double value : values) {
            double adjustedValue = value - compensation;
            double newSum = sum + adjustedValue;
            compensation = (newSum - sum) - adjustedValue;
            sum = newSum;
        }

        return sum;
    }

    // 5. 货币计算最佳实践
    public static void monetaryCalculation() {
        System.out.println("=== 货币计算比较 ===");

        // 错误做法:直接使用double
        double price1 = 0.1;
        double price2 = 0.2;
        double total1 = price1 + price2;
        System.out.println("double计算: " + price1 + " + " + price2 + " = " + total1);
        System.out.println("是否等于0.3: " + (total1 == 0.3));

        // 正确做法:使用BigDecimal
        BigDecimal bd1 = new BigDecimal("0.1");
        BigDecimal bd2 = new BigDecimal("0.2");
        BigDecimal total2 = bd1.add(bd2);
        System.out.println("BigDecimal计算: " + bd1 + " + " + bd2 + " = " + total2);
        System.out.println("是否等于0.3: " + total2.equals(new BigDecimal("0.3")));

        // 如果必须使用double,整数化处理
        long cents1 = Math.round(price1 * 100);
        long cents2 = Math.round(price2 * 100);
        long totalCents = cents1 + cents2;
        double total3 = totalCents / 100.0;
        System.out.println("整数化处理: " + total3);
    }

    // 6. 格式化输出
    public static void formatDouble(double value) {
        System.out.println("原始值: " + value);

        // 使用DecimalFormat
        DecimalFormat df1 = new DecimalFormat("#.##");
        DecimalFormat df2 = new DecimalFormat("0.000");
        DecimalFormat df3 = new DecimalFormat("#.##E0");

        System.out.println("保留2位小数: " + df1.format(value));
        System.out.println("固定3位小数: " + df2.format(value));
        System.out.println("科学计数法: " + df3.format(value));

        // 使用printf
        System.out.printf("printf %.2f%n", value);
        System.out.printf("printf %e%n", value);
        System.out.printf("printf %g%n", value);

        // 使用String.format
        System.out.println("String.format: " + String.format("%.4f", value));
    }

    // 7. 边界值处理
    public static boolean isValidNumber(double value) {
        return Double.isFinite(value);
    }

    public static double clamp(double value, double min, double max) {
        if (Double.isNaN(value)) return min;
        return Math.max(min, Math.min(max, value));
    }

    // 8. 数组操作优化
    public static double[] normalizeArray(double[] array) {
        if (array == null || array.length == 0) {
            return new double[0];
        }

        // 找到最大值
        double max = Double.NEGATIVE_INFINITY;
        for (double value : array) {
            if (Double.isFinite(value) && value > max) {
                max = value;
            }
        }

        if (max == 0.0 || !Double.isFinite(max)) {
            return array.clone();
        }

        // 归一化
        double[] normalized = new double[array.length];
        for (int i = 0; i < array.length; i++) {
            normalized[i] = Double.isFinite(array[i]) ? array[i] / max : 0.0;
        }

        return normalized;
    }

    public static void main(String[] args) {
        System.out.println("=== 浮点数比较 ===");
        double a = 0.1 + 0.2;
        double b = 0.3;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("直接比较 a == b: " + (a == b));
        System.out.println("绝对误差比较: " + doubleEquals(a, b));
        System.out.println("相对误差比较: " + doubleEqualsRelative(a, b, 1e-15));

        System.out.println("\n=== 安全运算 ===");
        System.out.println("safeDivide(1.0, 0.0): " + safeDivide(1.0, 0.0));
        System.out.println("safeSqrt(-1.0): " + safeSqrt(-1.0));
        System.out.println("safeLog(0.0): " + safeLog(0.0));

        System.out.println("\n=== 数值稳定求和 ===");
        double[] values = new double[1000000];
        for (int i = 0; i < values.length; i++) {
            values[i] = 0.1;
        }

        double simpleSum = 0.0;
        for (double value : values) {
            simpleSum += value;
        }

        double stableSum = stableSum(values);
        double expected = values.length * 0.1;

        System.out.println("期望值: " + expected);
        System.out.println("简单求和: " + simpleSum);
        System.out.println("稳定求和: " + stableSum);
        System.out.println("简单求和误差: " + Math.abs(simpleSum - expected));
        System.out.println("稳定求和误差: " + Math.abs(stableSum - expected));

        monetaryCalculation();

        System.out.println("\n=== 格式化输出 ===");
        formatDouble(123.456789);

        System.out.println("\n=== 数组归一化 ===");
        double[] testArray = {1.0, 2.5, 3.7, 0.8, 4.2};
        double[] normalized = normalizeArray(testArray);

        System.out.println("原数组: " + java.util.Arrays.toString(testArray));
        System.out.println("归一化: " + java.util.Arrays.toString(normalized));
    }
}

double类型是Java中精度最高的内置数值类型,适用于科学计算、工程计算、统计分析等需要高精度的场景。在货币计算中建议使用BigDecimal以避免精度问题。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-07-28 16:25:54

results matching ""

    No results matching ""