前端累加nan怎么解决_Jmetal遭遇NaN,Infinity

觉得有用的话,请点击右下角6eb55f27245c66e382a748be45f8b63a.gif

推荐给更多小伙伴 dc4f5d029a100ebee91b156717a735d1.pngneoken_xu562ba73404a4477e331fb1e7cd83c6ab.pngAsurada2015d7ce859c599090d98374ee171ffe8576.pngEvacloud

用我的AI大师码0519在滴滴云上购买GPU/vGPU/机器学习产品可享受9折优惠,点击www.didiyun.com前往滴滴云官网.
  • 首先NaN表示不是一个数,Infinity表示是一个无穷大的数
表达式     结果
Math.sqrt(-1.0)     -> NaN
0.0 / 0.0     -> NaN
1.0 / 0.0     -> 无穷大
-1.0 / 0.0     -> 负无穷大
NaN + 1.0     -> NaN
无穷大 + 1.0     -> 无穷大
无穷大 + 无穷大     -> 无穷大
NaN > 1.0     -> false
NaN == 1.0     -> false
NaN  false
NaN == NaN     -> false
0.0 == -0.01     -> true
  • 在Jmetal中,或者说EC中,出现 NaN , 有可能:
  1. 进化或者变异的时候出现了除数为0的情况,此时查看程序中出现的 除号后的分母部分
  2. 查看是否有开方操作,已经开方中的数是否为一个负数
  • 在Jmetal中,或者说EC中,出现 Inifinity , 有可能:
  1. 在计算拥挤距离时,边界点会被定义为Inifinity,如果有多个解的拥挤距离具有Inifinity的情况,则说明在边界点的位置有重复或者说是重叠的解
  2. 没有做边界判断,即决策变量具有越界的情况,导致目标函数的值编程一个极大值,或者导致一些指标算出来是一个Inf的值
  3. 一个数/Double.MIN_VALUE //所以说,没事干不要用MIN_VALUE89ace946fbab95e38f7074deb1928284.png
  • 认为设置MIN_VALUE为1E-20这样会比较香
  1. SBX操作上需要注意,自己写SBX函数时
  • 如果想要判断在什么时候出了问题,可以在这个可能的地方打上断点f48c2f803ff2da393b02e5fdf1e6c4d4.png
  • 注意打上条件断点,还要记得选中,否则也会出现断点无效的情况,接着就可以debug了60a23d07a42453711d7385f13a1f3532.png

举个例子

  • 在HMOMFMA中,我使用了MFEA-GHS中计算维度的平均值进行迁移的方法,在这种方法中计算的b_trans为-900,这是因为b这个维度的方差特别大,导致平均值和所选维度的差异十分巨大导致的,而在进行SBX杂交时,a的维度值为20,而b_trans为-900, 说白了,还是变量值越界了
b43bc6a7b3706bc58a1a51a92c451ec1.png
  • 仔细调试后发现是betaq越界了cd4758c6ab16c49bbcc4d83733867bf1.pngeec50f1028e700d0795b45231741a06f.png7d5c6529429d3ec5f5d7933d56c7d9cc.png

  • (1.0 / (2.0 - rand * alpha)=-0.0035335689045936395 , 1.0 / (distributionIndex_ + 1.0)=0.047619047619047616

  • 所以说,这应该是Math.pow()函数的锅,简单测试一下这个函数。

//        double test=Math.pow(0.1, -0.1);//1.2589254117941673
//        double test=Math.pow(0.01, -0.1);//1.5848931924611136
//        double test=Math.pow(0.001, -0.1);//1.9952623149688797
//        double test=Math.pow(-0.001, 0.1);//NaN
//        double test=Math.pow(-1, 0.1);//NaN
//        double test=Math.pow(-1, -0.1);//NaN
//        System.out.println(test);
  • 这样的话来说,当第一个值是负数,第二个值是小数就会出现这种情况。来看看API是怎么说的?!
  • 还真让我找到了~
     * If the first argument is finite and less than zero
     如果第一个参数是有限负数
     * 

     *  if the second argument is a finite even integer, the
     * result is equal to the result of raising the absolute value of
     * the first argument to the power of the second argument
     *
     第二个参数是有限偶整数,结果是power(a,b)的绝对值向上取整
     * if the second argument is a finite odd integer, the result
     * is equal to the negative of the result of raising the absolute
     * value of the first argument to the power of the second
     * argument
     第二个参数是有限奇整数,结果是power(a,b)的绝对值向上取整的负数
     * if the second argument is finite and not an integer, then
     * the result is NaN.
     如果第二个参数是有限的但不是整数,结果是NaN
0b7fef9ab753805c27d53263f82b2ddd.png
  • 解决方案,在b_trans处使用变量的边界加以约束
  • 当然,也可以自己重写SBX,即使超出边界,得到的也是边界值而不会是NaN 例如:
public static double SBXtoDouble(double parent1, double parent2, int k, int skillfactor) throws JMException {
        double rand = PseudoRandom.randDouble();
        double c1;
        double c2;
        double beta;
        double eta = 20.0;

        if (rand 0.5) {
            beta = Math.pow(rand * 2, 1.0 / (1.0 + eta));
        } else beta = Math.pow(1.0 / (2 - rand * 2), 1.0 / (1 + eta));
        c1 = 0.5 * ((1 + beta) * parent1 + (1 - beta) * parent2);
        c2 = 0.5 * ((1 - beta) * parent1 + (1 + beta) * parent2);
        //由于我们只要需要offSpring[0],因此对offSpring[0]进行约束
        if (c2 > 100) {
            c2 = 100;
        } else if (c2 100) {
            c2 = -100;
        }
        return c2;
    }

  • 因为AdvanceRandSBX具有一定的概率,不会每次都是NaN,但是大部分时候都会。但是得到NaN的原因是betaq变量的值。bec71ef7a8c486fabd33789e2a0f2a53.png
d41494bbf43222d40fb12aaa73ae3d39.png
  • 可以看出AdvanceRandSBX的值在非[0-1]区间上的随机性更强,但是还是很容易出现NaN,而相对的SBXtoDouble则会一直输出-100,其实本质上已经越界了~

  • 但是这不是绝对的-- 因为在Jmetal中的多项式变异函数也有这个缺陷,因为其默认都是使用[0,1]之间的的数值,因此多项式变异函数也要根据实际需要进行重写!!!

再举个多项式变异的例子

//Jmetal版本多项式变异
    public static double doMutation(double a) throws JMException {
        double rnd, delta1, delta2, mut_pow, deltaq;
        double y, yl, yu, val, xy;
        double eta_m_ = 20.0;
        double distributionIndex_ = 20.0;
        y = a;


        if (PseudoRandom.randDouble() <= 1) {//如果小于变异概率即可以进行变异操作

            yl = 0;
            yu = 1;
            delta1 = (y - yl) / (yu - yl);
            delta2 = (yu - y) / (yu - yl);
            rnd = PseudoRandom.randDouble();
            mut_pow = 1.0 / (eta_m_ + 1.0);
            if (rnd <= 0.5) {
                xy = 1.0 - delta1;
                val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (Math.pow(xy, (distributionIndex_ + 1.0)));
                deltaq = java.lang.Math.pow(val, mut_pow) - 1.0;
            } else {
                xy = 1.0 - delta2;
                val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (java.lang.Math.pow(xy, (distributionIndex_ + 1.0)));
                deltaq = 1.0 - (java.lang.Math.pow(val, mut_pow));
            }
            y = y + deltaq * (yu - yl);
            if (y                 y = yl;
            if (y > yu)
                y = yu;


        }
        return y;// for

    } // doMutation

    //Polynomial变量范围版本
    public static double MutationtoDouble(double a) throws JMException {
        double rnd, delta1, delta2, mut_pow, deltaq;
        double y, yl, yu, val, xy;
        double eta_m_ = 20.0;
        double distributionIndex_ = 20.0;
        y = a;


        if (PseudoRandom.randDouble() <= 1) {//如果小于变异概率即可以进行变异操作

            yl = -100.0;
            yu = 100.0;
            delta1 = (y - yl) / (yu - yl);
            delta2 = (yu - y) / (yu - yl);
            rnd = PseudoRandom.randDouble();
            mut_pow = 1.0 / (eta_m_ + 1.0);
            if (rnd <= 0.5) {
                xy = 1.0 - delta1;
                val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (Math.pow(xy, (distributionIndex_ + 1.0)));
                deltaq = java.lang.Math.pow(val, mut_pow) - 1.0;
            } else {
                xy = 1.0 - delta2;
                val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (java.lang.Math.pow(xy, (distributionIndex_ + 1.0)));
                deltaq = 1.0 - (java.lang.Math.pow(val, mut_pow));
            }
            y = y + deltaq * (yu - yl);
            if (y                 y = yl;
            if (y > yu)
                y = yu;


        }
        return y;// for

    } // doMutation
  • 这两个的区别,仅仅在于 yl = 0; yu = 1;yl = -100; yu = 100; 的差别,但是注意,实际问题中不可能问题的上下界限永远是[0,1], 在CIHS等MTOPs问题中,问题的上下界是[-100,100]. 而此时如果还是仅仅用[0,1]进行变异,如果a的值超过范围则生成的值是NaN.fff330b142144ba9277a446d9df9b490.png
  • deltaq = 1.0 - (java.lang.Math.pow(val, mut_pow)); ,因为此处val是负数,而mut_pow是小数。ac0bf3c59f09d4c221c5387faa6f6bd2.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值