精华内容
下载资源
问答
  • 电渗流在粗糙板上的流动特性分析。通过微扰法求得粗糙板电渗流半解析解,分析结果。
  • BAW美式期权定价半解析解 参考文献:G. Barone-Adesi & R. E. Whaley, Efficient Analytic Approximation of American Option Values, The Journal of Finance, No 2 (June 1987), 301-320 基本思想:美式期权...

    BAW美式期权定价半解析解

    参考文献:G. Barone-Adesi & R. E. Whaley, Efficient Analytic Approximation of American Option Values, The Journal of Finance, No 2 (June 1987), 301-320

    基本思想:美式期权不同于欧式期权之处在于,美式期权可以在到期日之前随时执行,因而美式期权的价值高于欧式期权。美式期权价值高于欧式期权的部分叫做美式期权溢价ϵc\epsilon_c,如下式所示:
    ϵc(S,T)=C(S,T)c(S,T), \epsilon_c\left( S , T \right) = C \left( S , T \right) -c \left( S , T \right) ,
    其中C(S,T)C \left( S , T \right)表示美式看涨期权的价值;c(S,T)c \left( S , T \right)表示欧式看涨期权的价值。

    根据Feynman_Kac定理,在无套利假设条件下,欧式期权价值和美式期权价值满足椭圆的偏微分方程,因而,风险溢价也应该满足以下的相同形式的椭圆偏微分方程:
    1/2σ2S2εSSrε+bSεS+εt=0(1) 1 / 2 \sigma^{2} S^{2} \varepsilon_{S S}-r \varepsilon+b S \varepsilon_{S}+\varepsilon_{t}=0\tag{1}
    做如下的变量替换:

    τ=Tt\tau = T -t 代表距离到期日T的时间;

    M=2r/σ2 和 N=2b/σ2M=2 r / \sigma^{2} \text { 和 } N=2 b / \sigma^{2}

    则式(1)可以重写为
    S2εSSMe+NSeS(M/r)ετ=0(2) S^{2} \varepsilon_{S S}-M_{e}+N S e_{S}-(M / r)\varepsilon_{\tau}=0\tag{2}
    定义美式期权的提前行权溢价满足如下的形式:
    ϵc(S,K)=K(τ)f(S,K) \epsilon_c(S, K)=K(\tau) f(S, K)
    其中K(T)=1erτ,K \left( T \right) = 1 - e ^ { - r \tau} , 则(2)式可以重写为
    S2fss+NSfs(M/K)f(1K)MfK=0(3) S^{2} f s s+N S f_{s}-(M / K) f-(1-K) M f_{K}=0\tag{3}
    敲黑板!!!BAW方法为何是半解析解,就在于我们要对式(3)进行简化,把最后一项省略掉,式(3)就可以变成一个二次常微分方程。那么最后一项为何可以省略掉呢?当商品期权距离到期日时间非常短(T=0)的时候,fKf_{K}接近于0,即执行价格对风险溢价几乎没影响。当商品期权距离到期日的时间非常长(τ=\tau=\infin)的时候,K=1则1-K=0。因而,ff可以通过近似求解以下的表达式得到:
    S2fss+NSfs(M/K)f=0 S^{2} f s s+N S f_{s}-(M / K) f=0
    假设f=aSqf=a S^{q},代入上式,可以得到两个特征根(M/K为正):
    q1=(N1)(N1)2+4M/K2<0 q _ {1} = - \left( N - 1 \right) - \frac{\sqrt { \left( N - 1 \right) ^ { 2 } + 4 M / K }}{2}<0

    q2=(N1)+(N1)2+4M/K2>0 q _ {2} = - \left( N - 1 \right) + \frac{\sqrt { \left( N - 1 \right) ^ { 2 } + 4 M / K }}{2}>0

    则有通解:
    f(S)=a1Sq1+a2Sq2, f \left( S \right) = a _ { 1 } S ^{ q _ { 1 } } + a _ { 2 } S ^{ q_2 } ,
    现在的问题是如何确定参数a1a_1a2a_2。这个问题要追溯到美式看涨期权的边值条件
    CS(S,τ)=1(B1) \frac{\partial C}{\partial S}(S^*,\tau)=1\tag{B1}

    C(0,τ)=0(B2) C(0,\tau)=0\tag{B2}

    C(S,τ)=SK(B3) C(S^*,\tau)=S^*-K\tag{B3}

    由(B2):C(0,τ)=c(0,τ)+K(τ)f(0)=0C(0,\tau)=c(0,\tau)+K(\tau)f(0)=0, 可以推出 f(0)=0f(0)=0,因而f(S)=a2Sq2(q1<0)f(S)=a _ { 2 } S ^{ q_2 }(q_1<0)

    由(B1):CS(S,τ)=cS(S,τ)+K(τ)fS\frac{\partial C}{\partial S}(S^*,\tau)=\frac{\partial c}{\partial S}(S^*,\tau)+K(\tau)\frac{\partial f}{\partial S} 可以推导出
    1=e(br)τ N[d1(S)]+Kq2a2Sq21 1=e^{(b-r) \tau} \mathrm{~N}\left[d_{1}\left(S^{*}\right)\right]+K q_{2} a_{2} S^{* q_{2}-1}
    这里用到了欧式期权的BS公式:
    c(S,T)=Se(br)T N(d1)XerT N(d2) c(S, T)=S e^{(b-r) T} \mathrm{~N}\left(d_{1}\right)-X e^{-r T} \mathrm{~N}\left(d_{2}\right)
    其中 d1=[ln(S/X)+(b+0.5σ2)T]/σT,d2=d1σTd_{1}=\left[\ln (S / X)+\left(b+0.5 \sigma^{2}\right) T\right] / \sigma \sqrt{T}, d_{2}=d_{1}-\sigma \sqrt{T}

    由此,可以求解出
    a2={1e(br)τ N[d1(S)]}/Kq2Sq21 a_{2}=\left\{1-e^{(b-r) \tau} \mathrm{~N}\left[d_{1}\left(S^{*}\right)\right]\right\} / K q_{2} S^{* q_{2}-1}
    由(B3)可以求解出最优执行边界满足以下的表达式
    SX=c(S,τ)+{1e(br)τ N[d1(S)]}S/q2 S^{*}-X=c\left(S^{*}, \tau\right)+\left\{1-e^{(b-r) \tau} \mathrm{~N}\left[d_{1}\left(S^{*}\right)\right]\right\} S^{*} / q_{2}
    综上所述,美式看涨期权的解析公式如下所示:
    C(S,τ)=c(S,τ)+A2(S/S)q2, when S<SC(S,τ)=SK, when SS \begin{array}{ll} C(S, \tau)=c(S, \tau)+A_{2}\left(S / S^{*}\right)^{q_{2}}, & \text { when } S<S^{*} \\ C(S, \tau)=S-K, & \text { when } S \geq S^{*} \end{array}
    其中 A2=(S/q2){1e(br)T N[d1(S)]}A_{2}=\left(S^{*} / q_{2}\right)\left\{1-e^{(b-r) T} \mathrm{~N}\left[d_{1}\left(S^{*}\right)\right]\right\}

    美式看跌期权与看涨期权的求解套路差不多:
    ϵp(S,T)=P(S,T)p(S,T) \epsilon_p\left( S , T \right) = P \left( S , T \right) -p \left( S , T \right)
    区别在于边界条件不同
    PS(S,τ)=1(B1) \frac{\partial P}{\partial S}(S^*,\tau)=-1\tag{B1}

    P(,τ)=0(B2) P(\infin,\tau)=0\tag{B2}

    P(S,τ)=KS(B3) P(S^*,\tau)=K-S^*\tag{B3}

    python程序实现:参考Python implementation of the Barone-Adesi And Whaley model for the valuation of American options and their greeks. · GitHub

    调用实例:

    from BAW import *
    import matplotlib.pyplot as plt
    
    Stock = []
    Put_American = []
    Put_European = []
    Expir = []
    K = 50
    
    for S in range(1,151,10):
        Stock.append(S)
        Expir.append(max(K-S,0))
        put_American = getValue('American', 'Value', 'Put', S, K, 5, 0.03, 0.02,0.5)
        put_European = getValue('European', 'Value', 'Put', S, K, 5, 0.03, 0.02,0.5)
        Put_American.append(put_American)
        Put_European.append(put_European)
        
    plt.plot(Stock, Put_American,linewidth=0.5,label='American Option Value')
    plt.plot(Stock, Put_European,'r-.',linewidth=0.5,label='European Option Value')
    plt.plot(Stock, Expir, 'g--',linewidth=0.5)
    plt.legend()
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Y1Qch1q-1618749362203)(C:\Users\Cathy&Allen\Documents\草稿\BAW.png)]

    展开全文
  • 根据纳比吉安电磁法书上公式自己编写的长导线均匀空间解析解的C/C++代码,跟数值解做了对比,是吻合的,希望对你们有所帮助!
  • 我们提出了半解析技术,用于在具有多... 我们的方法包括将问题简化为具有单个场的方程,找到近似解析解并对其进行扰动。 扰动可以以半解析形式编写。 我们断言我们的技术没有收敛问题,并在示例潜力上证明了收敛速度。
  • 在本文中,我们研究了模糊线性垂直渗透方程的,该方程代表了称为渗流区的那部分中多孔介质中的水运动。 该区域对于干旱地区非常重要,因为与其中水分含量有关的复杂现象。 这些现象涉及渗流带与大气之间的水分...
  • 读了个多月的《梦的解析》,总算看完了,其实最后三分之一我看的很随便,甚至经常走神,很是惭愧,因为后面有点看不懂了,也没什么吸引我的内容,就想混过去得了,要不剩下三分之一没有看感觉不完整。下次再看书的...

    读了半个多月的《梦的解析》,总算看完了,其实最后三分之一我看的很随便,甚至经常走神,很是惭愧,因为后面有点看不懂了,也没什么吸引我的内容,就想混过去得了,要不剩下三分之一没有看感觉不完整。下次再看书的时候还是要认真看的。

    看完之后,感觉这本书还是挺受争议的,有些观点都说服不了我这个外行人,当然我没有什么相关知识,从我的角度出发,能让我觉得很震撼的才叫好书。我感觉这本书研究意义很大,比较深奥,解开了我好多的疑惑,但是对于我来说也算不上特别优秀的书,豆瓣评分8.0分,作为一个阅读者,斗胆给弗洛伊德评7.5分。这本书我会一直留着,过一阵子再看应该会有新的感触。

    我们每个人都会做梦。在初中的时候我玩CF玩的很痴迷,有一天晚上我就梦到我被里面的僵尸挠了胳膊一下,当时我就觉得这个疼啊,我就很想快点变成僵尸得了,太疼了!那种疼痛感十分剧烈,十分真实,最后把我疼醒了,我当时看了一眼胳膊,好像是胳膊上的汗毛被凉席夹住了(记不太清了,太久远了)。当看完弗洛伊德的《梦的解析》时,我才知道梦是具有将微感官刺激放大的功能,所以那时的疼痛感是那么的真实。当看到这,豁然开朗,也解开了我多年的疑惑。

    有人说做梦会梦到未来发生的事情,按书中的内容来说的话,这是不可能的,我们可以梦到过去,但是不会预测未来。梦的材料永远都是来自现实世界的。当我们梦到某个女人时,醒来发现我们好像没有见过她,但事实上,在我们曾经的日子里,肯定见过她一眼,只不过在现实生活中我们没有刻意去记住她,梦到的东西有可能在生活中是记不起来的,所以我们经常会梦到一些在现实生活中无关紧要的事情。但是梦中的材料永远都是来自现实世界的。

    有的时候我们刚醒来会记得做了些什么梦,但是马上就会忘记,这也是正常的现象,因为有的梦是杂乱无序的。我们在现实生活中也可以发现,有逻辑的的思考可以记住更多的内容,拥有好的学习方法可以更高效的学习,但是有的梦没有规律,没有逻辑,所以我们忘记也是正常现象。还有一点原因是我上面提到的,有的梦会梦到一些无关紧要的东西,比较微弱,忘记也正常。第三点就是梦的兴趣,当我们做了一个特别离奇的梦,那么我们可能会记这个梦一辈子。但是大多数梦都没有什么意思,所以大家没有兴趣,也会忘记。

    影响做梦的因素有很多。环境因素就是其中的一点,打雷天梦到置身沙场、房门嘎嘎作响梦到窃贼入室、被子滑落梦到自己没有穿衣服等,我自己的经历是我梦到车牌打到了我的头上,醒来发现自己脑袋紧贴着墙壁。还有一点我觉得也算是环境因素,当我们睡觉的时候,其实还存在着感官刺激,这时如果我们听到有人叫我们的名字,可能会从梦中醒来,但是如果仅仅是一个无关紧要的词,是叫不醒我们的。另一因素就是身体的状况了,不同身体部位出现不同的疾病,就会有不同的梦。亚里士多德也指出过,疾病刚出现时,人在清醒状态下察觉不到,梦可能会提醒人们注意这一点。举一些例子,心脏病人的梦通常很短,经常会在惊惧中醒来,总是梦到恶劣环境下的死亡场景;肺病患者会梦到窒息、拥挤的场景;消化系统异常时,会出现厌恶美食的念头。我个人经常梦到有关牙齿的梦,因为我有磨牙的习惯。还有就是精神的刺激也会影响我们的梦,如果内心特别喜欢一个人,那么近期就很可能会梦到他(她);如果特别渴望考研成功,也许就会梦到上岸成功的梦。梦的材料也有可能来源于童年时期,这个大家应该都深有感触,总是梦到与自己小时候有关的梦,并且小时候的梦会有一些身体记忆存在的,我们有时候会梦到自己从高处掉下来就好像身体空了一样,这其实与我们小时候的经历有关,大多数人小时候都被亲人举高高过,扔过头顶然后再接住,那时我们就会笑的很开心、很兴奋,因为很刺激啊。现在当我们做从高处跌落的梦时,材料就源于童年时期的举高高。除此之外,还有我上面说的,近几天的一些印象深刻或者并非重要的事件也时成为影响我们梦的因素但是大多数梦的材料来源于当天的经历。

    弗洛伊德说梦都是愿望的达成,只不过好多愿望都被隐藏了。梦是愿望的达成这句话可以理解,我们经常会梦到一些有关我们愿望的梦,但是所有的梦都是愿望的达成吗,那些悲伤的梦境怎么解释呢?弗洛伊德始终坚持梦是愿望的达成这一观点,这里我就有一些不同的看法了,并且他举的有些例子没有说服我。我印象比较深刻的是这个例子,并且我觉得也比较有说服力来说明这一观点。有一个女孩儿,她很喜欢她姐姐的孩子,但是有一天她却梦到她姐姐的孩子离世了,躺在一个小盒子里面。这就是一个悲伤的梦,她也否认自己有她姐姐孩子离世的愿望,怎么会是愿望的达成?原因是这是她姐姐第二个孩子,第一个孩子已经离世了,这个女孩儿在屋子里参加她姐姐第一个孩子葬礼时,向窗外看到一个来参加葬礼的男子,她一眼就爱上了他,但是日后却没有再看到他了,所以她非常想再次见到这名男子,就做了一个有关葬礼的梦,因为这样才能达到她的愿望。所以,按照弗洛伊德的观点,梦都是愿望的达成,愿望是动机,表现的时候可能具有伪装性,是掩盖的,没有那么明显而已。并且我们在现实生活中有些愿望是不道德的、不被允许的,是被抑制的,这些在梦中都会有所体现,例如偷窃、和某位同事发生关系等,这些都是我们内心深处的愿望,所以梦会告诉我们内心最深处的想法曾经的愿望也会在梦中出现,如果我们曾经因为某些事情想要杀死某个人,这件事情可能会在梦中出现,但是当我们醒来就会觉得这太荒唐了,我现在根本就不讨厌他啊,这是因为杀死他是曾经的愿望。

    梦还会具有安抚的作用。作者举了一个例子,他梦到教皇死了,因为他被教堂里的钟声吵醒了,所以就会梦到一个报复性的梦。我上面所说的观点就是冰山一角,除此之外还有很多观点:“梦中梦”表达的就是现实,是真实的回忆;梦中具有替代作用,会梦到别的事物替代自己;有受虐倾向的人经常会做一些不愉快的梦,这是为了满足自己;高级智力在梦中会被取消,深思熟虑的事情不会在梦中出现,会出现没有考虑清楚的内容,所以当醒来会觉得梦中的自己做了这么傻的事情;梦都是利己主义的;连续长时间做的梦,往往会有一个共同的基础,例如对一个人的思念······

    我看完这本书之后,每天都会做梦,我也是服了,,,,,但是事实上,每个人每天都会做梦,只不过大多数人没有回忆而已,而我却对梦有了更高的注意力。并且做梦具有锻炼大脑的功能哦。

    总之,梦是一位良友、良伴,会给我们带来更多的乐趣。

    (如果觉得字数太多,红字内容是观点,可以扫一眼)

     

     

     

     

     

     

     

     

     

    展开全文
  • 新引擎仅解析分片上下文,对于 SQL 采用"理解"理念,进一步提升性能和兼容性,同时降低了代码复杂度(不理解没关系,我们后续会更新文章解释该优点)。 国内另一款数据库中间件 MyCAT SQL 解析引擎也是 Druid,...

    1. 概述

    SQL 解析引擎,数据库中间件必备的功能和流程。Sharding-JDBC 在 1.5.0.M1 正式发布时,将 SQL 解析引擎从 Druid 替换成了自研的。新引擎仅解析分片上下文,对于 SQL 采用"半理解"理念,进一步提升性能和兼容性,同时降低了代码复杂度(不理解没关系,我们后续会更新文章解释该优点)。 国内另一款数据库中间件 MyCAT SQL 解析引擎也是 Druid,目前也在开发属于自己的 SQL 解析引擎。

    可能有同学看到SQL 解析会被吓到,请淡定,耐心往下看。《SQL 解析》内容我们会分成 5 篇相对简短的文章,让大家能够相对轻松愉快的去理解:

    1. 词法解析
    2. 插入 SQL 解析
    3. 查询 SQL 解析
    4. 更新 SQL 解析
    5. 删除 SQL 解析

    SQL 解析引擎在 parsing 包下,如上图所见包含两大组件:

    1. Lexer:词法解析器。
    2. Parser:SQL解析器。

    两者都是解析器,区别在于 Lexer 只做词法的解析,不关注上下文,将字符串拆解成 N 个词法。而 Parser 在 Lexer 的基础上,还需要理解 SQL 。打个比方:

    SQL :SELECT * FROM t_user  
    Lexer :[SELECT] [ * ] [FROM] [t_user]  
    Parser :这是一条 [SELECT] 查询表为 [t_user] ,并且返回 [ * ] 所有字段的 SQL。
    

    不完全懂?没关系,本文的主角是 Lexer,我们通过源码一点一点理解。一共 1400 行左右代码左右,还包含注释等等,实际更少噢。

    2. Lexer 词法解析器

    Lexer 原理顺序顺序顺序 解析 SQL,将字符串拆解成 N 个词法。

    核心代码如下:

    // Lexer.java
    public class Lexer {
    
        /**
         * 输出字符串
         * 比如:SQL
         */
        @Getter
        private final String input;
        /**
         * 词法标记字典
         */
        private final Dictionary dictionary;
        /**
         * 解析到 SQL 的 offset
         */
        private int offset;
        /**
         * 当前 词法标记
         */
        @Getter
        private Token currentToken;
    
        /**
         * 分析下一个词法标记.
         *
         * @see #currentToken
         * @see #offset
         */
        public final void nextToken() {
            skipIgnoredToken();
            if (isVariableBegin()) { // 变量
                currentToken = new Tokenizer(input, dictionary, offset).scanVariable();
            } else if (isNCharBegin()) { // N\
                currentToken = new Tokenizer(input, dictionary, ++offset).scanChars();
            } else if (isIdentifierBegin()) { // Keyword + Literals.IDENTIFIER
                currentToken = new Tokenizer(input, dictionary, offset).scanIdentifier();
            } else if (isHexDecimalBegin()) { // 十六进制
                currentToken = new Tokenizer(input, dictionary, offset).scanHexDecimal();
            } else if (isNumberBegin()) { // 数字(整数+浮点数)
                currentToken = new Tokenizer(input, dictionary, offset).scanNumber();
            } else if (isSymbolBegin()) { // 符号
                currentToken = new Tokenizer(input, dictionary, offset).scanSymbol();
            } else if (isCharsBegin()) { // 字符串,例如:"abc"
                currentToken = new Tokenizer(input, dictionary, offset).scanChars();
            } else if (isEnd()) { // 结束
                currentToken = new Token(Assist.END, "", offset);
            } else { // 分析错误,无符合条件的词法标记
                currentToken = new Token(Assist.ERROR, "", offset);
            }
            offset = currentToken.getEndPosition();
            // System.out.println("| " + currentToken.getLiterals() + " | " + currentToken.getType() + " | " + currentToken.getEndPosition() + " |");
        }
        /**
         * 跳过忽略的词法标记
         * 1. 空格
         * 2. SQL Hint
         * 3. SQL 注释
         */
        private void skipIgnoredToken() {
            // 空格
            offset = new Tokenizer(input, dictionary, offset).skipWhitespace();
            // SQL Hint
            while (isHintBegin()) {
                offset = new Tokenizer(input, dictionary, offset).skipHint();
                offset = new Tokenizer(input, dictionary, offset).skipWhitespace();
            }
            // SQL 注释
            while (isCommentBegin()) {
                offset = new Tokenizer(input, dictionary, offset).skipComment();
                offset = new Tokenizer(input, dictionary, offset).skipWhitespace();
            }
        }
    }

    通过 #nextToken() 方法,不断解析出 Token(词法标记)。我们来执行一次,看看 SQL 会被拆解成哪些 Token。 

    SQL :SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=? AND o.order_id=?
    
    literals TokenType类 TokenType值 endPosition
    SELECT DefaultKeyword SELECT 6
    i Literals IDENTIFIER 8
    . Symbol DOT 9
    * Symbol STAR 10
    FROM DefaultKeyword FROM 15
    t_order Literals IDENTIFIER 23
    o Literals IDENTIFIER 25
    JOIN DefaultKeyword JOIN 30
    t_order_item Literals IDENTIFIER 43
    i Literals IDENTIFIER 45
    ON DefaultKeyword ON 48
    o Literals IDENTIFIER 50
    . Symbol DOT 51
    order_id Literals IDENTIFIER 59
    = Symbol EQ 60
    i Literals IDENTIFIER 61
    . Symbol DOT 62
    order_id Literals IDENTIFIER 70
    WHERE DefaultKeyword WHERE 76
    o Literals IDENTIFIER 78
    . Symbol DOT 79
    user_id Literals IDENTIFIER 86
    = Symbol EQ 87
    ? Symbol QUESTION 88
    AND DefaultKeyword AND 92
    o Literals IDENTIFIER 94
    . Symbol DOT 95
    order_id Literals IDENTIFIER 103
    = Symbol EQ 104
    ? Symbol QUESTION 105
      Assist END 105

    眼尖的同学可能看到了 Tokenizer。对的,它是 Lexer 的好基佬,负责分词

    我们来总结下,Lexer#nextToken() 方法里,使用 #skipIgnoredToken() 方法跳过忽略的 Token,通过 #isXXXX() 方法判断好下一个 Token 的类型后,交给 Tokenizer 进行分词返回 Token。‼️此处可以考虑做个优化,不需要每次都 new Tokenizer(...) 出来,一个 Lexer 搭配一个 Tokenizer。


    由于不同数据库遵守 SQL 规范略有不同,所以不同的数据库对应不同的 Lexer。

    子 Lexer 通过重写方法实现自己独有的 SQL 语法。

    3. Token 词法标记

    上文我们已经看过 Token 的例子,一共有 3 个属性:

    • TokenType type :词法标记类型
    • String literals :词法字面量标记
    • int endPosition :literals 在 SQL 里的结束位置

    TokenType 词法标记类型,一共分成 4 个大类:

    • DefaultKeyword :词法关键词
    • Literals :词法字面量标记
    • Symbol :词法符号标记
    • Assist :词法辅助标记

    3.1 DefaultKeyword 词法关键词

    不同数据库有自己独有的_词法关键词_,例如 MySQL 熟知的分页 Limit。

    我们以 MySQL 举个例子,当创建 MySQLLexer 时,会加载 DefaultKeyword 和 MySQLKeyword( OracleLexer、PostgreSQLLexer、SQLServerLexer 同 MySQLLexer )。核心代码如下:

    // MySQLLexer.java
    public final class MySQLLexer extends Lexer {
    
        /**
         * 字典
         */
        private static Dictionary dictionary = new Dictionary(MySQLKeyword.values());
        
        public MySQLLexer(final String input) {
            super(input, dictionary);
        }
    }
    
    // Dictionary.java
    public final class Dictionary {
    
        /**
         * 词法关键词Map
         */
        private final Map<String, Keyword> tokens = new HashMap<>(1024);
        
        public Dictionary(final Keyword... dialectKeywords) {
            fill(dialectKeywords);
        }
    
        /**
         * 装上默认词法关键词 + 方言词法关键词
         * 不同的数据库有相同的默认词法关键词,有有不同的方言关键词
         *
         * @param dialectKeywords 方言词法关键词
         */
        private void fill(final Keyword... dialectKeywords) {
            for (DefaultKeyword each : DefaultKeyword.values()) {
                tokens.put(each.name(), each);
            }
            for (Keyword each : dialectKeywords) {
                tokens.put(each.toString(), each);
            }
        }
    }

    Keyword 与 Literals.IDENTIFIER 是一起解析的,我们放在 Literals.IDENTIFIER 处一起分析。

    3.2 Literals 词法字面量标记

    Literals 词法字面量标记,一共分成 6 种:

    • IDENTIFIER :词法关键词
    • VARIABLE :变量
    • CHARS :字符串
    • HEX :十六进制
    • INT :整数
    • FLOAT :浮点数

    3.2.1 Literals.IDENTIFIER 词法关键词

    词法关键词。例如:表名,查询字段 等等。

    解析 Literals.IDENTIFIER 与 Keyword 核心代码如下:

    // Lexer.java
    private boolean isIdentifierBegin() {
       return isIdentifierBegin(getCurrentChar(0));
    }
    private boolean isIdentifierBegin(final char ch) {
       return CharType.isAlphabet(ch) || '`' == ch || '_' == ch || '$' == ch;
    }
    
    // Tokenizer.java
    /**
    * 扫描标识符.
    *
    * @return 标识符标记
    */
    public Token scanIdentifier() {
       // `字段`,例如:SELECT `id` FROM t_user 中的 `id`
       if ('`' == charAt(offset)) {
           int length = getLengthUntilTerminatedChar('`');
           return new Token(Literals.IDENTIFIER, input.substring(offset, offset + length), offset + length);
       }
       int length = 0;
       while (isIdentifierChar(charAt(offset + length))) {
           length++;
       }
       String literals = input.substring(offset, offset + length);
       // 处理 order / group 作为表名
       if (isAmbiguousIdentifier(literals)) {
           return new Token(processAmbiguousIdentifier(offset + length, literals), literals, offset + length);
       }
       // 从 词法关键词 查找是否是 Keyword,如果是,则返回 Keyword,否则返回 Literals.IDENTIFIER
       return new Token(dictionary.findTokenType(literals, Literals.IDENTIFIER), literals, offset + length);
    }
    /**
    * 计算到结束字符的长度
    *
    * @see #hasEscapeChar(char, int) 处理类似 SELECT a AS `b``c` FROM table。此处连续的 "``" 不是结尾,如果传递的是 "`" 会产生误判,所以加了这个判断
    * @param terminatedChar 结束字符
    * @return 长度
    */
    private int getLengthUntilTerminatedChar(final char terminatedChar) {
       int length = 1;
       while (terminatedChar != charAt(offset + length) || hasEscapeChar(terminatedChar, offset + length)) {
           if (offset + length >= input.length()) {
               throw new UnterminatedCharException(terminatedChar);
           }
           if (hasEscapeChar(terminatedChar, offset + length)) {
               length++;
           }
           length++;
       }
       return length + 1;
    }
    /**
    * 是否是 Escape 字符
    *
    * @param charIdentifier 字符
    * @param offset 位置
    * @return 是否
    */
    private boolean hasEscapeChar(final char charIdentifier, final int offset) {
       return charIdentifier == charAt(offset) && charIdentifier == charAt(offset + 1);
    }
    private boolean isIdentifierChar(final char ch) {
       return CharType.isAlphabet(ch) || CharType.isDigital(ch) || '_' == ch || '$' == ch || '#' == ch;
    }
    /**
    * 是否是引起歧义的标识符
    * 例如 "SELECT * FROM group",此时 "group" 代表的是表名,而非词法关键词
    *
    * @param literals 标识符
    * @return 是否
    */
    private boolean isAmbiguousIdentifier(final String literals) {
       return DefaultKeyword.ORDER.name().equalsIgnoreCase(literals) || DefaultKeyword.GROUP.name().equalsIgnoreCase(literals);
    }
    /**
    * 获取引起歧义的标识符对应的词法标记类型
    *
    * @param offset 位置
    * @param literals 标识符
    * @return 词法标记类型
    */
    private TokenType processAmbiguousIdentifier(final int offset, final String literals) {
       int i = 0;
       while (CharType.isWhitespace(charAt(offset + i))) {
           i++;
       }
       if (DefaultKeyword.BY.name().equalsIgnoreCase(String.valueOf(new char[] {charAt(offset + i), charAt(offset + i + 1)}))) {
           return dictionary.findTokenType(literals);
       }
       return Literals.IDENTIFIER;
    }

    3.2.2 Literals.VARIABLE 变量

    变量。例如:SELECT @@VERSION 。

    解析核心代码如下:

    // Lexer.java
    /**
    * 是否是 变量
    * MySQL 与 SQL Server 支持
    * 
    * @see Tokenizer#scanVariable()
    * @return 是否
    */
    protected boolean isVariableBegin() {
       return false;
    }
    
    // Tokenizer.java
    /**
    * 扫描变量.
    * 在 MySQL 里,@代表用户变量;@@代表系统变量。
    * 在 SQLServer 里,有 @@。
    *
    * @return 变量标记
    */
    public Token scanVariable() {
       int length = 1;
       if ('@' == charAt(offset + 1)) {
           length++;
       }
       while (isVariableChar(charAt(offset + length))) {
           length++;
       }
       return new Token(Literals.VARIABLE, input.substring(offset, offset + length), offset + length);
    }

    3.2.3 Literals.CHARS 字符串

    字符串。例如:SELECT "123" 。

    解析核心代码如下:

    // Lexer.java
    /**
    * 是否 N\
    * 目前 SQLServer 独有:在 SQL Server 中處理 Unicode 字串常數時,必需為所有的 Unicode 字串加上前置詞 N
    *
    * @see Tokenizer#scanChars()
    * @return 是否
    */
    private boolean isNCharBegin() {
       return isSupportNChars() && 'N' == getCurrentChar(0) && '\'' == getCurrentChar(1);
    }
    private boolean isCharsBegin() {
       return '\'' == getCurrentChar(0) || '\"' == getCurrentChar(0);
    }
    
    // Tokenizer.java
    /**
    * 扫描字符串.
    *
    * @return 字符串标记
    */
    public Token scanChars() {
       return scanChars(charAt(offset));
    }
    private Token scanChars(final char terminatedChar) {
       int length = getLengthUntilTerminatedChar(terminatedChar);
       return new Token(Literals.CHARS, input.substring(offset + 1, offset + length - 1), offset + length);
    }

    3.2.4 Literals.HEX 十六进制 

    // Lexer.java
    /**
    * 是否是 十六进制
    *
    * @see Tokenizer#scanHexDecimal()
    * @return 是否
    */
    private boolean isHexDecimalBegin() {
       return '0' == getCurrentChar(0) && 'x' == getCurrentChar(1);
    }
    
    // Tokenizer.java
    /**
    * 扫描十六进制数.
    *
    * @return 十六进制数标记
    */
    public Token scanHexDecimal() {
       int length = HEX_BEGIN_SYMBOL_LENGTH;
       // 负数
       if ('-' == charAt(offset + length)) {
           length++;
       }
       while (isHex(charAt(offset + length))) {
           length++;
       }
       return new Token(Literals.HEX, input.substring(offset, offset + length), offset + length);
    }
    

    3.2.5 Literals.INT 整数

    整数。例如:SELECT * FROM t_user WHERE id = 1

    Literals.INT 与 Literals.FLOAT 是一起解析的,我们放在 Literals.FLOAT 处一起分析。

    3.2.6 Literals.FLOAT 浮点数

    浮点数。例如:SELECT * FROM t_user WHERE id = 1.0。 浮点数包含几种:"1.0","1.0F","7.823E5"(科学计数法)。

    解析核心代码如下:

    // Lexer.java
    /**
    * 是否是 数字
    * '-' 需要特殊处理。".2" 被处理成省略0的小数,"-.2" 不能被处理成省略的小数,否则会出问题。
    * 例如说,"SELECT a-.2" 处理的结果是 "SELECT" / "a" / "-" / ".2"
    *
    * @return 是否
    */
    private boolean isNumberBegin() {
       return CharType.isDigital(getCurrentChar(0)) // 数字
               || ('.' == getCurrentChar(0) && CharType.isDigital(getCurrentChar(1)) && !isIdentifierBegin(getCurrentChar(-1)) // 浮点数
               || ('-' == getCurrentChar(0) && ('.' == getCurrentChar(0) || CharType.isDigital(getCurrentChar(1))))); // 负数
    }
    
    // Tokenizer.java
    /**
    * 扫描数字.
    * 解析数字的结果会有两种:整数 和 浮点数.
    *
    * @return 数字标记
    */
    public Token scanNumber() {
       int length = 0;
       // 负数
       if ('-' == charAt(offset + length)) {
           length++;
       }
       // 浮点数
       length += getDigitalLength(offset + length);
       boolean isFloat = false;
       if ('.' == charAt(offset + length)) {
           isFloat = true;
           length++;
           length += getDigitalLength(offset + length);
       }
       // 科学计数表示,例如:SELECT 7.823E5
       if (isScientificNotation(offset + length)) {
           isFloat = true;
           length++;
           if ('+' == charAt(offset + length) || '-' == charAt(offset + length)) {
               length++;
           }
           length += getDigitalLength(offset + length);
       }
       // 浮点数,例如:SELECT 1.333F
       if (isBinaryNumber(offset + length)) {
           isFloat = true;
           length++;
       }
       return new Token(isFloat ? Literals.FLOAT : Literals.INT, input.substring(offset, offset + length), offset + length);
    }

    这里要特别注意下:"-"。在数字表达实例,可以判定为 负号 和 减号(不考虑科学计数法)。

    • ".2" 解析结果是 ".2"
    • "-.2" 解析结果不能是 "-.2",而是 "-" 和 ".2"。

    3.3 Symbol 词法符号标记

    词法符号标记。例如:"{", "}", ">=" 等等。

    解析核心代码如下:

    // Lexer.java
    /**
    * 是否是 符号
    *
    * @see Tokenizer#scanSymbol()
    * @return 是否
    */
    private boolean isSymbolBegin() {
       return CharType.isSymbol(getCurrentChar(0));
    }
    
    // CharType.java
    /**
    * 判断是否为符号.
    *
    * @param ch 待判断的字符
    * @return 是否为符号
    */
    public static boolean isSymbol(final char ch) {
       return '(' == ch || ')' == ch || '[' == ch || ']' == ch || '{' == ch || '}' == ch || '+' == ch || '-' == ch || '*' == ch || '/' == ch || '%' == ch || '^' == ch || '=' == ch
               || '>' == ch || '<' == ch || '~' == ch || '!' == ch || '?' == ch || '&' == ch || '|' == ch || '.' == ch || ':' == ch || '#' == ch || ',' == ch || ';' == ch;
    }
    
    // Tokenizer.java
    /**
    * 扫描符号.
    *
    * @return 符号标记
    */
    public Token scanSymbol() {
       int length = 0;
       while (CharType.isSymbol(charAt(offset + length))) {
           length++;
       }
       String literals = input.substring(offset, offset + length);
       // 倒序遍历,查询符合条件的 符号。例如 literals = ";;",会是拆分成两个 ";"。如果基于正序,literals = "<=",会被解析成 "<" + "="。
       Symbol symbol;
       while (null == (symbol = Symbol.literalsOf(literals))) {
           literals = input.substring(offset, offset + --length);
       }
       return new Token(symbol, literals, offset + length);
    }

    3.4 Assist 词法辅助标记

    Assist 词法辅助标记,一共分成 2 种:

    • END :分析结束
    • ERROR :分析错误。
    展开全文
  • 作为一个长期关注家电行业和家电产品的“专业人士”,我就经常会收到朋友关于空气净化器选购及使用的咨询,在网上也看到过非常多人对于这个产品的质疑或困惑。今天,我就以个人经验,针对这些问题来谈谈我的看法。...

    空气净化器应该不算是新兴家电了,尤其是经过前几年雾霾天的洗礼,很多人家里都买了空气净化器,现在说起这个产品,相信很少人还会不认识。

    但认识归认识,是不是真的会用又是另一回事了。作为一个长期关注家电行业和家电产品的“半专业人士”,我就经常会收到朋友关于空气净化器选购及使用的咨询,在网上也看到过非常多人对于这个产品的质疑或困惑。

    今天,我就以个人经验,针对这些问题来谈谈我的看法。

    疑问1:现在雾霾天少多了,还需不需要置办空气净化器?

    解答:

    空气污染是现代生活的常态。的确,经过近几年大气污染的治理,现在雾霾天的出现真的没有以前频繁了,但时不时地还是会发生。

    我有朋友在北京生活,上周告诉我有几天刮起了非常严重的沙尘暴,那叫一个飞沙走石啊,空气中满满的土味,即使是戴着口罩,仍然能强烈的感受到土味钻进鼻孔和肺部的不适,PM2.5指数天天爆表,达到250+。

    当然,刨去这些极端天气,更多的时候空气污染指数显示为“良”,极少数为“优”,除非你住在森林里、海洋边。比如今天,PM20为98,PM2.5为17,很显然,这样“良”的空气质量并不能令人满意,更完全达不到“健康”的要求。

    aa2ba21c298c445bdf5f4ad43ec5dae9.png

    因此,对于这个问题我的回答是需要,当然需要。

    我尽管是一个人居住,但我家里有3台空气净化器,1台是5年前买的飞利浦的大众款,1台是去年松下的最新款,还有1台是刚刚买的康佳的最新款。

    b676e668c2f30460e7520eb2d7c05bf1.png

    其实,室内的空气污染不光来自窗外,现在家里自发产生的污染源也有很多,比如新装修不久的房子持续析出的甲醛、TVOC(一种有害气体),比如花粉、尘螨和宠物皮屑等容易导致人们过敏的源头,再比如各种各样的异味,包括食物残渣没有及时倾倒发酵发臭了,或者家里养了宠物,宠物代谢物、猫粮狗粮等也都会散发异味。因此,借助空气净化器来实现室内空气的净化绝对是刚需。

    另外,每台空气净化器都有一定的适用面积,从十几平米到几十平米不等,但无论如何,它的净化面积不可能覆盖全屋。除非你愿意走到哪里,把它挪到哪里,否则在客厅、卧室等不同家居空间放置多台空气净化器很有必要。

    疑问2:空净自带的数显可不可信?档位怎么选择更合理?

    解答:

    坦白讲,大多数空气净化器液晶屏上的数据显示只能仅供参考,因为它们的空气质量检测元件不太靠谱,而且当空气质量发生变化时,这些元件的反应往往也比较迟缓。像我买的第一台飞利浦的空气净化器就存在非常严重的这方面的问题。

    很多人使用空气净化器时习惯开到自动档或最大档,但如果产品本身对空气质量的判断就不准确,开到自动档岂不是意义不大?而开到最大档的话,噪音值和耗电量都会大大飙升,如果空气质量并没有那么糟糕,这就会带来很大的损失和听觉上的不适,因此我不推荐。

    个人建议是额外购置一个单独功能的空气质量测试仪,京东、天猫等电商平台上有很多,价格并不贵,通常几十块到一两百块就够了,品牌我就不推介了,大家找专业品牌和口碑好的就错不了。

    然后,大家就可以根据这个专业的空气质量测试仪上的指数来决定所需的空气净化器档位,虽然多了一个步骤,但总体效果会更好。

    疑问3:最近需要购置空气净化器,但不知道应该怎么选择。

    解答:

    就像前面说的,现在室内空气的污染源其实很多,因此,大众对于空气净化器功能的要求已经非常多元化了,净化需求会比较复杂,希望产品能全面应对这些污染源。

    然而,让空气净化器对这么多的污染源“雨露均沾”是一件十分困难的事情,即使做到了,整体效果也未见得会好。另外,各家各户的实际情况不一样,最大程度上解决特定家庭最突出的室内空气污染问题,才是目前阶段比较理想的方案。

    所以,我建议你们先考虑清楚自家最需要解决的空气污染问题是什么。如果是新装修的房子,想要清除甲醛、TVOC等有害气体,那就去看除醛能力特别强的空气净化器,如果是易敏人群、有老人的、有小孩的,可以优先选择除过敏原能力强的,如果家里养了宠物,或者有烟民,那就应该找除异味能力更强的。

    情况比较复杂,或者仍举棋不定的网友,我觉得可以了解一下松下最新推出的芯替式空气净化器。它在功能和设计上有个很大的颠覆,就是它提供了除醛滤网、过敏原滤网和宠物滤网三种选择,只需一台机器,使用者可以根据自己的家居环境和需求自由选择。滤网尺寸都是一样的,安装和替换都很方便,如果有一天家里的净化需求变了,比如新婚不久宝宝诞生了,那换个滤网就行,不需要因此换掉一整台空气净化器。

    65a54a6fd3178af22c9681ef36f2635f.png

    疑问4:空气净化器用了一段时间开始产生酸味,这是怎么回事?

    解答:

    这是一个很普遍的问题,原因在于目前市场上绝大部分的空气净化器都是采用单纯的活性炭物理吸附的方式,因此,用的久了,活性炭达到饱和,就会返出酸味,这相当于对室内空气进行了二次污染。

    现在针对这个问题,更好的解决方法是用化学分解的方式来清除这些污染源,因为比起吸附,化学分解是通过化学反应生成对人体无害的含氮化合物,去除甲醛等有害物更彻底,同时,还不会因活性炭饱和而导致二次散发的酸味,两全其美。刚才提到的松下芯替式空气净化器就是在滤网上涂上特殊配方的化学成分来分解有害物的,安全可靠。

    除了这种根本的解决方案外,空气净化器的日常养护也需要引起大家的注意。很多消费者都是光用产品,不保养。其实,用了一段时间之后,大家都应该把滤网拆下来,放到太阳能直射到的地方晒一晒,这样可以帮助活性炭过滤网自动完成脱附除尘,“满血复活”,发酸的问题就可以得到阶段性的解决,此外,如果空气净化器还有过滤毛发等大颗粒物质的初效滤网,也应该经常拆下来清洗一下。有了良好的后续维护,空气净化器才能发挥最大的净化效能。

    887b7cdb85a23b62c8a870d94b36ea3e.png

    后再来做下总结。在我看来,空气净化器绝对是最值得买的家电产品之一,现在室内空气污染源很多,我们在选购空气净化器时应首先考虑到自身的使用需求,找到更合适的产品去解决净化的主要矛盾,另外,在后期使用中大家也得上点心,并不是买回来用就完了,保养好了,产品的净化效果才能最大化,使用寿命也会更长。

    展开全文
  • 通过对该相位响应的解析解进行微分,建立了WBG时延谱的半解析型通解。基于该时延谱通解,仿真分析了均匀和线性啁啾WBG的时延谱,并与用其他方法得到的时延谱及其实测谱进行对比分析,以验证时延谱通解的分析精度和...
  • matlab微分方程

    2020-07-16 23:34:42
    首先要明确的一点就是,我们求微分方程的时候,要注意有解析解和数值解,解析解又有通解和特解,这在我们编写代码的时候可以通过初始点的值来获得特解。其实今天老师讲的还挺不错的,举出了很多的例子,基本上与物理...
  • 微平行管道内两层牛顿流体的非定常电渗流动,苏洁,菅永军,运用拉普拉斯变换法,给出了平行微管道间两层电渗流瞬时速度的半解析解。解析求解了线性的Poisson-Boltzmann方程和非定常的柯西动量方�
  • 通过微扰理论求得非线性薛定谔方程(NLSE)的时域半解析解,在非线性效应增大的情况下提出了优化微扰方法(MPM),并在多跨距非线性光纤链路中与原微扰方法(PM)进行了对比仿真研究。研究结果表明,优化微扰方法在非线性效应...
  • 位错环导致的多层薄板界面弹性场分析,夏热,吴文旺,本文基于离散快速傅里叶变换方式发展了一套半解析解用于分析多层薄板结构的位错环状态。主要针对两层绑定系统进行了详细的分析讨
  • 根据某污水处理工程中一圆形贮液池的设计资料,描述了地下式圆形贮液池的荷载分布特点...将推导的解析解与通过有限元分析软件ANSYS计算求得的数值解进行了对比,结果表明两者符合较好,从而验证了所推导解析解的正确性。
  • 海平面上升对海岸潮差响应的理论解析,王伟,,应用海湾和封闭矩形海域改进的Taylor问题的研究海平面上升对M2分潮旋转潮波系统及沿岸潮差的变化。将南黄海概化为一等深矩形海�
  • 其實兩方面都可以並行,但是並行SQL線程的收益更大,因為SQL線程做的事情更多(解析,執行)。並行IO線程,可以將從Master拉取和寫Relay log分為兩個線程;並行SQL線程則可以根據需要做到庫級並行,表級並行,事務級並...
  • 通过沃尔泰拉(Volterra)级数理论求得了非线性薛定谔方程(NLSE)的半解析解,在考虑光纤损耗、色散及非线性效应的情况下,推出了长距离在线级联掺铒光纤放大器(EDFA)光纤通信系统中信号和自发辐射噪声(ASE)之间耦合串扰...
  • Prototype1.4.0 源码解析

    2012-05-10 16:26:00
    本来就不会用Prototype框架,所以对某些方法理解也是半解,带<?>的我都不敢确定。 注释结合了一些实例,比较容易理解,有些地方上下结合的看起来有些费力,这里多亏webStorm 编辑器的ctrl+shift+i 的调出...
  • 综合考虑压裂后裂缝未完全穿透地层厚度及致密气藏应力敏感性基础上,建立了致密气藏多段压裂水平井非稳态渗流模型,通过Laplace变换和无限傅立叶余弦变换得到了该模型半解析解。计算结果表明,致密气藏流体流动可划分为...
  • 为分析分形油藏渗流机理,基于分段压裂水平井渗流特征,建立了分形油藏分段压裂水平井试井解释模型,应用Laplace变换和Stehfest数值反演求得了定产条件下不同边界类型分形油藏分段压裂水平井井底压力半解析解....
  • 利用级数收敛理论, 推导出了基于Volterra级数理论的非线性薛定谔方程(NLSE)半解析解的收敛性质的表达式, 得到了保证级数收敛所允许的光脉冲最大输入功率、传输距离和所用Volterra级数模型的阶数以及与光纤参数之间的...
  • 将非均质冻结壁的温度场等效为抛物线形分布,考虑冻结壁内部土体的卸载作用,基于粘弹性理论结合数值积分方法推导了非均质冻结壁的应力场与位移场的半解析解表达式。对比分析了在冻结壁卸载初期到井壁完成施工的24h的...
  • 我们还研究了旋转浓缩暗物质晕的塌陷/扩展,并找到了使用变量分离方法得出的一系列流体动力学演化方程的精确半解析解。 还获得了流体流动方程的近似一阶解。 塌陷/膨胀凝结水暗物质晕的径向坐标相关质量,密度和...
  • 漫射光谱技术对生物组织进行快速和无创测量具有非常重要的意义,但精确解析解的缺乏限制了该技术的有效应用。基于Monte Carlo模拟数据研究了一个适用于小孔径测量漫反射的经验解析模型,建立了反射率随孔径和生物...
  • 今天的大数据概念解析,我们来讲讲分布式存储与数据库。进入大数据时代,数据特征发生了明显的变化,数据规模大、非结构化/结构化的数据多,使得大数据存储本身也需要克服很多的问题。要实现大规模数据的计算分析...
  • 1)这个题如果用java,相对会好一些,因为可以直接用JDK中的Point2D类,来定义坐标系空间中的一个点。 2)简单思路:暴力破解,计算任意两个点之间的距离,时间负责度为O(n^2); 3)优化思路:《编程之美》上给出...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 155
精华内容 62
热门标签
关键字:

半解析解