Научитесь настраивать и писать свои собственные теги с помощью JSTL
. Заметьте, что EL - это EviL (исключения времени выполнения, рефакторинг). Калитка также может быть злой (производительность, трудная для небольших приложений или простой уровень обзора). Пример из java2s ,
Это должно быть добавлено в веб-приложение web.xml
<taglib>
<taglib-uri>/java2s</taglib-uri>
<taglib-location>/WEB-INF/java2s.tld</taglib-location>
</taglib>
создать файл: java2s.tld в / WEB-INF /
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- a tab library descriptor -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Java2s Simple Tags</short-name>
<!-- this tag manipulates its body content by converting it to upper case
-->
<tag>
<name>bodyContentTag</name>
<tag-class>com.java2s.BodyContentTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>howMany</name>
</attribute>
</tag>
</taglib>
скомпилировать следующий код в WEB-INF \ classes \ com \ java2s
package com.java2s;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class BodyContentTag extends BodyTagSupport{
private int iterations, howMany;
public void setHowMany(int i){
this.howMany = i;
}
public void setBodyContent(BodyContent bc){
super.setBodyContent(bc);
System.out.println("BodyContent = '" + bc.getString() + "'");
}
public int doAfterBody(){
try{
BodyContent bodyContent = super.getBodyContent();
String bodyString = bodyContent.getString();
JspWriter out = bodyContent.getEnclosingWriter();
if ( iterations % 2 == 0 )
out.print(bodyString.toLowerCase());
else
out.print(bodyString.toUpperCase());
iterations++;
bodyContent.clear(); // empty buffer for next evaluation
}
catch (IOException e) {
System.out.println("Error in BodyContentTag.doAfterBody()" + e.getMessage());
e.printStackTrace();
} // end of catch
int retValue = SKIP_BODY;
if ( iterations < howMany )
retValue = EVAL_BODY_AGAIN;
return retValue;
}
}
Запустить сервер и загрузить bodyContent.jsp в браузере
<%@ taglib uri="/java2s" prefix="java2s" %>
<html>
<head>
<title>A custom tag: body content</title>
</head>
<body>
This page uses a custom tag manipulates its body content.Here is its output:
<ol>
<java2s:bodyContentTag howMany="3">
<li>java2s.com</li>
</java2s:bodyContentTag>
</ol>
</body>
</html>
(a + p <= b) && (a != 1) && (b - a - p != 1);
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
с тех пор a> =0 (положительные целые числа), термин (== 0 || a> 1) всегда верен
если ((a+p) < = b) тогда (b> = p) верен, когда a, b, p> =0
поэтому ((a+p) < = b) & & (== 0 || a> 1) & & (b> = p)) & & ((b - (+ p) == 0), уменьшает до
b>=(a+p)
(b - (+ p) == 0) || (b - (+ p)>, 1) эквивалентно b> = (a+p)
поэтому, целое уравнение уменьшает до
**b>= (a+p)**
b >= (a+p) && a>=1
даже b >= p
избыточно, поскольку это будет всегда иметь место для a >= 1
Первое повторение:
bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);
return bool1 && bool2;
1111-секундное повторение:
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
Третье повторение (все положительные стороны)
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a != 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
4-е повторение (все положительные стороны)
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (b - p >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
5-е повторение:
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
Я чувствую (a! = 1) & & (+ p < = b) & & (+ p! = b - 1) немного более ясно. Другая опция:
интервал t = b-p; (a! = 1 & & < = t & & a! = t-1)
В основном или 0, t, или находится между 2 и t-2 включительно.
На этот вопрос довольно удобно ответили уже на практике, но существует один момент, который я упоминаю, ниже которого я не видел, что кто-либо еще повышает все же.
, Так как нам сказали принять a> = 0, и первое условие гарантирует, что b - (+ p)> = 0, на кронштейнах || тесты могут быть превращены в тесты против неравенства с 1:
(+ p < = b) & & (a! = 1) & & (b> = p) & & (b - p! = 1)
заманчиво удалить проверку (b> = p), который дал бы выражение nickf. И это - почти наверняка корректное практическое решение. К сожалению, мы должны знать больше о проблемной области перед способностью сказать, безопасно ли сделать это.
, Например, при использовании C и 32-разрядный неподписанный ints для типов a, b, и p, рассматривают случай где = 2^31 + 7, p = 2^31 + 5, b = 13. У нас есть a> 0, (+ p) = 12 < b, но b < p. (Я использую '^' для указания на возведение в степень, не C поразрядный xor.)
, Вероятно, Ваши значения не приблизятся к виду диапазонов, где этот вид переполнения является проблемой, но необходимо проверить это предположение. И если это оказывается возможностью, добавьте комментарий с тем выражением, объяснив это так, чтобы некоторый рьяный будущий оптимизатор небрежно не удалял (b> = p) тест.
(((a+p) < = b) & & (== 0 || a> 1) & & (b> = p)) & & ((b - (+ p) == 0) || (b - (+ p)> 1))
1) (== 0 || a> 1) (a! = 1)
2) (b> = p) (b - p> = 0)
(+ p < = b) (b - p> = a), который более силен, чем (b - p> = 0).
Первое условие уменьшило до [1 112] (a! = 1) & & (b - p> = a).
3) (b - (+ p) == 0) (b - p == 0), (b - p == a).
(b - (+ p)> 1) (b - p> 1) (b - p> 1 + a).
, Так как мы имели (b - p> = a) и мы используем & & операция, мы можем сказать что (b - p> = покрытия a) (b - p == & & b - p> 1 + a).
Следовательно, целое условие будет уменьшено до
(a! = 1 & & (b - p> = a))
существует tempation для сокращения его далее до (b> = p), но это сокращение не покроет запрет на b = p + 1, поэтому (a! = 1 & & (b - p> = a)), условие.
Хорошо, я надеюсь, что сделал свою математику прямо здесь, но если я прав, тогда это упрощает вполне немного. Предоставленный это не выглядит одинаково в конце, но логика ядра должна быть тем же.
// Initial equation
(((a + p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// ((a + p) <= b) iif a = 0 && p = b; therefore, b = p and a = 0 for this to work
(b == p) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// Simplification, assuming that b = p and a = 0
(b == p) && (a == 0)
Однако, если мы действуем под предположением, что нуль ни один положителен или отрицателен тогда, это подразумевает, что любое значение для предоставленного уравнению будет больше, чем или равный одному. Это в свою очередь означает, что уравнение будет всегда , оценивают ко лжи вследствие того, что следующее:
(a == 0 || a > 1)
только оценил бы к истинному когда a> = 2; однако, если следующее также верно:
(b >= p)
Тогда это означает, что p, по крайней мере, равен b, таким образом:
((a + p) <= b)
заменой становится:
((2 + b) <= b)
, Который никогда не может ясно оценивать к истинному.
как о следующей логике, прокомментируйте его:
((a == 0 || a > 1) && ((b-p) > 1) )
Если a, b и p являются положительными целыми числами (предполагающий, что положительный диапазон включает эти 0 значений) тогда выражение (((a+p) < = b) & & (== 0 || a> 1) & & (b> = p)) & & ((b - (+ p) == 0), || (b - (+ p)> 1)) может быть уменьшен до ((a+p) < =b) & & (a! =1) & & ((b-(a+p))! =1)
Позволяют мне продемонстрировать его: В первой части выражения существует условие, ((a+p) < =b) , что, если оценено истинный рендеринг, верный вторая часть: ((b - (+ p) == 0) || (b - (+ p)> 1)) . Если это верно, что (b> = (a+p)) тогда (b - (a+p)) должны быть больше или равными 0 , мы должны гарантировать что (b-(a+p))! =1 . Отложите этот термин некоторое время и продолжите.
Теперь мы можем сконцентрировать наши усилия на первая часть (((a+p) < = b) & & (== 0 || a> 1) & & (b> = p)) & & ((b-(a+p))! =1)
, Если положительно тогда, что это всегда> =0 и таким образом, мы можем отбросить тест (== 0 || a> 1) если польза (a! =1), и уменьшают первую часть выражения к [1 117] (((a+p) < = b) & & (b> = p) & & (a! =1)) .
Для следующего шага сокращения можно полагать, что, если b> = (a+p) тогда, очевидно b> =p ( положительно) и выражение могут быть уменьшены до
((a+p) < =b) & & (a! =1) & & ((b-(a+p))! =1)
Я добавил это как комментарий к ответу nickf, но думал, что предложу его как ответ на своем собственном. Хорошие ответы все, кажется, изменение его, включая мой. Но так как мы не в зависимости от компилятора для оптимизации (если бы OP были, мы даже не сделали бы этого), тогда кипятящий это по сравнению с 3 ANDs к следующим средствам, что будут значения, где только 2 из этих 3 частей должны будут быть оценены. И если бы это делается в сценарии, это имело бы значение в противоположность скомпилированному коду.
(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))
На основе комментария, я собираюсь добавить этот wrt этот являющийся лучше, чем И версия:
я предполагаю, что это зависит от того, больше ли Ваш истинный набор данных результатов, чем 50 процентов входных наборов. Чем чаще вход верен, тем лучше мое изменение будет. Так, с этим уравнением это похоже, И стиль будет лучше (по крайней мере, для моего набора входных данных 0-500).
Хорошо
((b - (a + p) == 0) || (b - (a + p) > 1))
Would be better writen as:
(b - (a + p) >= 0)
Applying this to the whole string you get:
((a+p) <= b) && (a > 1) && (b >= p)) && (b - (a + p) >= 0)
(a + p) <= b is the same thing as b - (a + p) >= 0
, Таким образом, можно избавиться от того отъезда:
((a+p) <= b) && (a > 1) && (b >= p))
// In one line:
return (a != 1) && ((b-a-p == 0) || (b-a-p > 1))
// Expanded for the compiler:
if(a == 1)
return false;
int bap = b - a - p;
return (bap == 0) || (bap > 1);
при регистрации процессора Вы используете, я могу оптимизировать для блока. =]
Это столь просто, как я мог получить его.
def calc(a, b, p):
if (a != 1):
temp = a - b + p
if temp == 0 or temp < -1:
return True
return False
Это могло также быть записано как:
def calc(a, b, p):
temp = a - b + p
return a != 1 and (temp == 0 or temp < -1)
Или как:
def calc(a, b, p):
temp = a - b + p
return a != 1 and temp <= 0 and temp != -1
Протестированный с a, b, p от 0 до 10 000:
a != 1 && a != (b-p-1) && a <= (b-p);
я думаю, что это может быть упрощено еще больше.
bap = b - (a + p)
bap >= 0 && bap != 1 && a != 1
РЕДАКТИРОВАНИЕ: Теперь я имею-2 для честной попытки выручения и также для того, что, кажется, мне действительный ответ. Для Вас, кто может использовать Python, вот две функции, один с вопросом и один с моим ответом:
def question(a, b, p):
return (((a+p) <= b) and (a == 0 or a > 1) and (b >= p)) or ((b - (a + p) == 0) or (b - (a + p) > 1))
def answer(a, b, p):
bap = b - (a + p)
return bap >= 0 and bap != 1 and a != 1
s = a + p
b >= s && a != 1 && b - s - 1 > 0
Проверено, возвращает то же логическое значение, что и вопрос.
Программа, которую я использовал для проверки: (весело писал ее)
#include <iostream>
using namespace std;
typedef unsigned int uint;
bool condition(uint a, uint b, uint p)
{
uint s = a + p;
return uint( b >= s && a != 1 && b - s - 1 > 0 )
== uint( (((a+p) <= b) && (a == 0 || a > 1) && (b >= p))
&& ((b - (a + p) == 0) || (b - (a + p) > 1)) );
}
void main()
{
uint i = 0;
uint j = 0;
uint k = 0;
const uint max = 50;
for (uint i = 0; i <= max; ++i)
for (uint j = 0; j <= max; ++j)
for (uint k = 0; k <= max; ++k)
if (condition(i, j, k) == false)
{
cout << "Fails on a = " << i << ", b = " << j;
cout << ", p = " << k << endl;
int wait = 0;
cin >> wait;
}
}
Так как ints не подписаны, (== 0 || a> 1) может быть заменен (a! =1).
С первой передачей, можно уменьшить его до этого:
uint sum = a + p;
return ((sum <= b) && (a != 1) && (b >= p)) && (b - sum != 1);
кроме того, это было бы намного более читаемо, если бы Вы смогли дать больше понятных имен переменным. Например, если бы a и p были давлениями, то a+p мог быть substitued как PressureSum.
Поскольку все они являются положительными целыми числами, большая часть повторений может быть удалена:
Таким образом, в качестве первого шага
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
становится
((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1)
Для для ясности, это просто замена паттерна (foo == 0 || foo > 1)
на foo != 1
Этот паттерн появляется дважды выше, один раз с foo = a и один раз с foo = (b - (a+p))
Я не сделал бы всей математики в том выражении. Такой, поскольку b - (+ p) оценен дважды. Если возможно, разделяет их на переменные вместо этого.
кроме того, пишущий полировку notiation дерево мог бы помочь Вам оптимизировать его, все, что Вы видите дважды, может быть снова использован.
(a!=1) && ((b==a+p) || (b>1+a+p))
Это может быть не самое простое, но должно быть одним из самых читаемых.
b >= p && b != p+1
РЕДАКТИРОВАНИЕ: хорошо, который не работал, но этот делает:
a != 1 && b >= a+p && b-a-p != 1
Рефакторинг для простоты, введя больше локальных переменных, которые указывают значение каждого выражения. Это трудно для нас, не имея представления о том, что означают a, b и p.
Если формула работает, и произойдите из своих бизнес-правил нет никакой реальной потребности упростить ее. Компилятор, вероятно, знает лучше, чем мы как к оптимизации формулы.
единственная вещь, которую необходимо сделать, использовать лучшие имена переменных, которые отражают бизнес-логику.
Остерегаются применения любого предлагаемого решения перед поблочным тестированием их.
jjngy здесь имеет его правильный. Вот доказательство, что его упрощенная формула эквивалентна исходному использованию Помощник Доказательства Coq .
Require Import Arith.
Require Import Omega.
Lemma eq : forall (a b p:nat),
(((a+p) <= b) /\ ((a = 0) \/ (a > 1)) /\ (b >= p)) /\
((b - (a + p) = 0) \/ (b - (a + p) > 1)) <->
((a + p <= b) /\ ~ (a= 1) /\ ~ (b - a - p = 1)).
Proof. intros; omega. Qed.
мои извинения за ошибку в исходной деривации. Это - то, что происходит, когда Вы не беспокоитесь к модульному тесту после рефакторинга!
исправленная деривация следует, в форме тестовой программы.
Короткий ответ:
((a > 1) && (skeet == 0)) || ((a > 1) && (jon > 0) && (skeet < -1));
где
jon = (b - p)
skeet = (a - jon);
class Program
{
static void Main(string[] args)
{
bool ok = true;
for (int a = 1; a < 100; a++)
{
Console.Write(a.ToString());
Console.Write("...");
for (int b = 1; b < 100; b++)
{
for (int p = 1; p < 100; p++)
{
bool[] results = testFunctions(a, b, p);
if (!allSame(results))
{
Console.WriteLine(string.Format(
"Fails for {0},{1},{2}", a, b, p));
for (int i = 1; i <= results.Length; i++)
{
Console.WriteLine(i.ToString() + ": " +
results[i-1].ToString());
}
ok = false;
break;
}
}
if (!ok) { break; }
}
if (!ok) { break; }
}
if (ok) { Console.WriteLine("Success"); }
else { Console.WriteLine("Failed!"); }
Console.ReadKey();
}
public static bool allSame(bool[] vals)
{
bool firstValue = vals[0];
for (int i = 1; i < vals.Length; i++)
{
if (vals[i] != firstValue)
{
return false;
}
}
return true;
}
public static bool[] testFunctions(int a, int b, int p)
{
bool [] results = new bool[16];
//given: all values are positive integers
if (a<=0 || b<=0 || p<=0)
{
throw new Exception("All inputs must be positive integers!");
}
//[1] original expression
results[0] = (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[2] a==0 cannot be true since a is a positive integer
results[1] = (((a+p) <= b) && (a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[3] rewrite (b >= p) && ((a+p) <= b)
results[2] = (b >= p) && (b >= (a+p)) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[4] since a is positive, (b>=p) guarantees (b>=(p+a)) so we
//can drop the latter term
results[3] = (b >= p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[5] separate the two cases b>=p and b=p
results[4] = ((b==p) && (a > 1) && ((b - (a + p) == 0) ||
(b - (a + p) > 1))) || ((b > p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1)));
//[6] rewrite the first case to eliminate p (since b=p
//in that case)
results[5] = ((b==p) && (a > 1) && ((-a == 0) ||
(-a > 1))) || ((b > p) && (a > 1) &&
(((b - a - p) == 0) || ((b - a - p) > 1)));
//[7] since a>0, neither (-a=0) nor (-a>1) can be true,
//so the case when b=p is always false
results[6] = (b > p) && (a > 1) && (((b - a - p) == 0) ||
((b - a - p) > 1));
//[8] rewrite (b>p) as ((b-p)>0) and reorder the subtractions
results[7] = ((b - p) > 0) && (a > 1) && (((b - p - a) == 0) ||
((b - p - a) > 1));
//[9] define (b - p) as N temporarily
int N = (b - p);
results[8] = (N > 0) && (a > 1) && (((N - a) == 0) || ((N - a) > 1));
//[10] rewrite the disjunction to isolate a
results[9] = (N > 0) && (a > 1) && ((a == N) || (a < (N - 1)));
//[11] expand the disjunction
results[10] = ((N > 0) && (a > 1) && (a == N)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[12] since (a = N) in the first subexpression we can simplify to
results[11] = ((a == N) && (a > 1)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[13] extract common term (a > 1) and replace N with (b - p)
results[12] = (a > 1) && ((a == (b - p)) ||
(((b - p) > 0) && (a < (b - p - 1))));
//[14] extract common term (a > 1) and replace N with (b - p)
results[13] = (a > 1) && (((a - b + p) == 0) ||
(((b - p) > 0) && ((a - b + p) < -1)));
//[15] replace redundant subterms with intermediate
//variables (to make Jon Skeet happy)
int jon = (b - p);
int skeet = (a - jon); //(a - b + p) = (a - (b - p))
results[14] = (a > 1) && ((skeet == 0) ||
((jon > 0) && (skeet < -1)));
//[16] rewrite in disjunctive normal form
results[15] = ((a > 1) && (skeet == 0)) ||
((a > 1) && (jon > 0) && (skeet < -1));
return results;
}
}